net.peanuuutz.fork.ui.internal.util.Preload.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fork-ui Show documentation
Show all versions of fork-ui Show documentation
Comprehensive API designed for Minecraft modders
The newest version!
package net.peanuuutz.fork.ui.internal.util
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import kotlinx.coroutines.launch
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.widget.EmptyWidget
import net.minecraft.client.util.math.MatrixStack
import net.peanuuutz.fork.coroutine.core.ForkClientMainScope
import net.peanuuutz.fork.coroutine.core.delayTicks
import net.peanuuutz.fork.event.client.ClientReloadEvents
import net.peanuuutz.fork.render.screen.draw.Drawer
import net.peanuuutz.fork.ui.animation.animateDecay
import net.peanuuutz.fork.ui.animation.animateInt
import net.peanuuutz.fork.ui.animation.rememberUpdatedTransition
import net.peanuuutz.fork.ui.foundation.animation.AnimatedVisibility
import net.peanuuutz.fork.ui.foundation.draw.Canvas
import net.peanuuutz.fork.ui.foundation.input.rememberContentScrollState
import net.peanuuutz.fork.ui.foundation.layout.Box
import net.peanuuutz.fork.ui.foundation.layout.grid.GridCells
import net.peanuuutz.fork.ui.foundation.layout.grid.HorizontalGrid
import net.peanuuutz.fork.ui.foundation.layout.grid.VerticalGrid
import net.peanuuutz.fork.ui.foundation.layout.list.Column
import net.peanuuutz.fork.ui.foundation.layout.maxSize
import net.peanuuutz.fork.ui.foundation.layout.offset
import net.peanuuutz.fork.ui.foundation.layout.popup.NoopPopupPositioner
import net.peanuuutz.fork.ui.foundation.layout.size
import net.peanuuutz.fork.ui.foundation.text.ClickableText
import net.peanuuutz.fork.ui.foundation.text.HoverableText
import net.peanuuutz.fork.ui.foundation.text.InteractableText
import net.peanuuutz.fork.ui.preset.Background
import net.peanuuutz.fork.ui.preset.Button
import net.peanuuutz.fork.ui.preset.Checkbox
import net.peanuuutz.fork.ui.preset.Divider
import net.peanuuutz.fork.ui.preset.HorizontalScrollbar
import net.peanuuutz.fork.ui.preset.Icon
import net.peanuuutz.fork.ui.preset.IconButton
import net.peanuuutz.fork.ui.preset.Panel
import net.peanuuutz.fork.ui.preset.PanelInset
import net.peanuuutz.fork.ui.preset.Slider
import net.peanuuutz.fork.ui.preset.Switch
import net.peanuuutz.fork.ui.preset.Text
import net.peanuuutz.fork.ui.preset.TextDivider
import net.peanuuutz.fork.ui.preset.TextField
import net.peanuuutz.fork.ui.preset.TooltipArea
import net.peanuuutz.fork.ui.preset.VerticalScrollbar
import net.peanuuutz.fork.ui.preset.icons.Icons8
import net.peanuuutz.fork.ui.preset.icons.Sword
import net.peanuuutz.fork.ui.preset.theme.Theme
import net.peanuuutz.fork.ui.scene.component.ComposeComponent
import net.peanuuutz.fork.ui.scene.component.DelegatingNativeWidget
import net.peanuuutz.fork.ui.ui.context.LocalContext
import net.peanuuutz.fork.ui.ui.draw.canvas.EmptyCanvas
import net.peanuuutz.fork.ui.ui.draw.text.Paragraph
import net.peanuuutz.fork.ui.ui.modifier.Modifier
import net.peanuuutz.fork.util.fork.ForkLogger
internal object Preload :
ComposeComponent(EmptyCanvas),
ClientLifecycleEvents.ClientStarted,
ClientReloadEvents.EndReloadResourcesListener
{
private val matrices: MatrixStack = MatrixStack()
@Composable
override fun Content() {
Theme {
Box(
modifier = Modifier.maxSize(100, 100)
) {
// States
var trigger by remember { mutableStateOf(false) }
// Animations
val transition = rememberUpdatedTransition(trigger)
val int by transition.animateInt { state -> if (state) 0 else 100 }
// Effects
SideEffect {
trigger = true
}
LaunchedEffect(Unit) {
animateDecay(
initialValue = 0.0f,
initialVelocity = 100.0f
) { _, _ ->
// ...
}
}
// Components
val moveAway = Modifier.offset(40, 40)
AnimatedVisibility(
isVisible = trigger
) {
Switch(
isChecked = false,
onValueChanged = { /* ... */ },
modifier = moveAway
)
}
Background {
Slider(
value = 0.0f,
onValueChanged = { /* ... */ },
range = 0.0f..1.0f,
modifier = moveAway
)
}
Button(
onClick = { /* ... */ },
modifier = moveAway
) {
Canvas(
modifier = Modifier.size(int)
) {
// ...
}
}
Checkbox(
isChecked = false,
onValueChanged = { /* ... */ }
)
ClickableText(
paragraph = Paragraph.Empty,
onClick = { /* ... */ }
)
Column {
DelegatingNativeWidget(
factory = { EmptyWidget(0, 0) }
)
}
HorizontalGrid(
rows = GridCells.fixedSize(10)
) {
HoverableText(
paragraph = Paragraph.Empty,
onHover = { /* ... */ }
)
}
HorizontalScrollbar(
scrollState = rememberContentScrollState(),
modifier = moveAway
)
IconButton(
onClick = { /* ... */ },
modifier = moveAway
) {
Icon(
spec = Icons8.TextureSpec,
region = Icons8.Sword
)
}
InteractableText(
paragraph = Paragraph.Empty,
onHover = { /* ... */ },
onClick = { /* ... */ }
)
Panel {
PanelInset {
TextDivider(paragraph = Paragraph.Empty)
}
}
Slider(
value = true,
onValueChanged = { /* ... */ },
values = listOf(true, false),
modifier = moveAway
)
TextField(
text = "",
onCandidate = { false },
modifier = moveAway
)
TooltipArea(
tooltip = { /* ... */ },
context = LocalContext.current,
positioner = NoopPopupPositioner
) {
Text(text = "Preload")
}
VerticalGrid(
columns = GridCells.List
) {
Divider()
}
VerticalScrollbar(
scrollState = rememberContentScrollState(),
modifier = moveAway
)
}
}
}
override fun onClientStarted(client: MinecraftClient) {
ForkLogger.debug("Start UI Preload")
// ScreenCanvas underlying renderer, which at this stage won't
// draw anything because resources are reloading (splash screen)
Drawer.drawText(matrices, "", 0.0f, 0.0f)
// We dispatch some tasks in advance, so that when player first
// enter a Compose based content, it won't lag for too long
init()
render(matrices, 0, 0, 0.0f)
mouseMoved(0.1, 0.1)
}
override fun onEndReloadResources(client: MinecraftClient, isSuccessful: Boolean) {
// Schedule more tasks on the next tick for layered content
// (TooltipArea) to come in, then dispose this component
ForkClientMainScope.launch {
render(matrices, 0, 0, 0.0f)
delayTicks(1L)
render(matrices, 0, 0, 0.0f)
delayTicks(1L)
render(matrices, 0, 0, 0.0f)
dispose()
ForkLogger.debug("End UI Preload")
}
}
}