Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layout modifiers #10

Merged
merged 9 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/gradle-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 17
java-version: 21
cache: gradle

- name: Build
Expand Down
49 changes: 27 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,23 @@

# Guiy

[![Java CI with Gradle](https://github.com/MineInAbyss/guiy-compose/actions/workflows/gradle-ci.yml/badge.svg)](https://github.com/MineInAbyss/guiy-compose/actions/workflows/gradle-ci.yml)
[![Maven](https://img.shields.io/maven-metadata/v?metadataUrl=https://repo.mineinabyss.com/releases/com/mineinabyss/guiy-compose/maven-metadata.xml)](https://repo.mineinabyss.com/#/releases/com/mineinabyss/guiy-compose)
[![Contribute](https://shields.io/badge/Contribute-e57be5?logo=github%20sponsors&style=flat&logoColor=white)](https://wiki.mineinabyss.com/contribute/)
</div>

A Spigot/PaperMC UI library built on the [Jetpack Compose](https://developer.android.com/jetpack/compose) compiler.
A Minecraft UI library for PaperMC, built on the [Jetpack Compose](https://developer.android.com/jetpack/compose)
compiler.

If you are new to Compose, please read the link above. In short, it is a declarative UI library that makes working with
state nice, gives easy access to coroutines, and helps write complex UI faster.
Compose is commonly used in Android (and cross-platform) development, so many resources are available online to learn
the basics. It makes it much easier to work with changing UI state and has built in support for Kotlin Coroutines.

## Beta status

We can't promise api stability yet, for the most part none of the existing elements should ever break entirely, but we
may change some behaviour like how `Grid` organizes itself.
> [!NOTE]
> Guiy is in active development as we continue to try new use-cases in our plugins. We can't promise api stability yet,
> but try to follow semver for breaking changes.

## Examples

See the `guiy-example` package for a full demonstration, below are snippets.
See the `guiy-example` package for a full demonstration of project setup and different features.

### Entry

Expand Down Expand Up @@ -65,23 +64,31 @@ We use a similar modifier system to Jetpack Compose.
```kotlin
// Entry to modifiers, though you are encouraged to pass a modifier parameter into your composables.
Modifier
// Set the size of an element (can use min/max constraints too)
.size(width = 2, height = 2)
// Place at an absolute offset
.at(x = 1, y = 5)
// Set the width of an element (can use min/max constraints, or .size to set width and height)
.width(3)
// Fill based on parent constraints like Jetpack
.fillmaxHeight()
// Padding in # of blocks
.padding(vertical = 1)
// Place at an offset
.offset(x = 1, y = 5)
// Do actions on click
.clickable { doSomething() }
```

### Alignment

Guiy provides Row, Column, and Box components based on Jetpack's, these come with Arrangement and Alignment too. We also
provide our components like Vertical/Horizontal Grids optimized for common Minecraft uses.

```kotlin
// A horizontal group of 10 items
Row {
repeat(10) {
// A horizontal row of 10 items, with 1 space between each.
Row(horizontalArrangement = Arrangement.spacedBy(1)) {
repeat(4) {
Item(...)
}
}

// Same but vertical
Column { ... }

Expand All @@ -91,8 +98,8 @@ Column {
Row { ... }
}

// Items aligned left to right, top to bottom, wrapped to be smaller than width.
Grid(Modifier.width(3)) {
// Items aligned left to right, top to bottom, wrapped to be smaller than width, useful for pages of items!
VerticalGrid(Modifier.width(3)) {
repeat(7) {
Item(...)
}
Expand Down Expand Up @@ -164,15 +171,13 @@ pluginManagement {

### Server setup

Guiy does not package the Kotlin runtime in itself, it uses our library idofront to load shared dependencies in an
isolated way.
Guiy does not package the Kotlin runtime, it depends on our helper plugin Idofront using Paper's isolated dependency
system.

- [Download](https://github.com/MineInAbyss/guiy-compose/releases/latest) and install Guiy into your plugin folder.
- [Download](https://github.com/MineInAbyss/Idofront/releases/latest) Idofront, a required dependency.
- Depend on Guiy in a [paper-plugin](https://docs.papermc.io/paper/dev/getting-started/paper-plugins), this will give you access to Guiy and any libraries in Idofront in an isolated manner.

There is currently no support for shading guiy.

## Thanks

- Google for creating Jetpack Compose.
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
kotlin.code.style=official
group=com.mineinabyss
version=0.11
version=0.12
idofrontVersion=0.24.1
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.mineinabyss.guiy.example

import com.mineinabyss.guiy.example.gui.AnimatedTitle
import com.mineinabyss.guiy.example.gui.CreativeMenu
import com.mineinabyss.guiy.example.gui.Cursor
import com.mineinabyss.guiy.example.gui.PaginatedMenu
import com.mineinabyss.guiy.example.gui.*
import com.mineinabyss.guiy.inventory.guiy
import com.mineinabyss.idofront.commands.execution.IdofrontCommandExecutor
import com.mineinabyss.idofront.commands.extensions.actions.playerAction
Expand All @@ -14,6 +11,13 @@ import org.bukkit.command.TabCompleter
class GuiyCommands(val plugin: GuiyExamplePlugin) : IdofrontCommandExecutor(), TabCompleter {
override val commands = commands(plugin) {
"guiyexample" {
"arrangement" {
playerAction {
guiy {
ArrangementMenu(player)
}
}
}
"animated" {
playerAction {
guiy {
Expand Down Expand Up @@ -52,6 +56,6 @@ class GuiyCommands(val plugin: GuiyExamplePlugin) : IdofrontCommandExecutor(), T
args: Array<out String>?
): List<String> =
if (command.name == "guiyexample")
listOf("animated", "creative", "cursor", "pagination")
listOf("arrangement", "animated", "creative", "cursor", "pagination")
else listOf()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.mineinabyss.guiy.example.gui

import androidx.compose.runtime.Composable
import com.mineinabyss.guiy.components.Item
import com.mineinabyss.guiy.components.canvases.Chest
import com.mineinabyss.guiy.inventory.LocalGuiyOwner
import com.mineinabyss.guiy.jetpack.Arrangement
import com.mineinabyss.guiy.layout.Column
import com.mineinabyss.guiy.layout.Row
import com.mineinabyss.guiy.modifiers.Modifier
import com.mineinabyss.guiy.modifiers.fillMaxSize
import com.mineinabyss.guiy.modifiers.fillMaxWidth
import org.bukkit.Material
import org.bukkit.entity.Player

@Composable
fun ArrangementMenu(player: Player) {
val owner = LocalGuiyOwner.current
Chest(
setOf(player),
"Arrangement example",
onClose = { owner.exit() },
modifier = Modifier.fillMaxSize()
) {
Column {
val modifier = Modifier.fillMaxWidth()
Row(modifier, horizontalArrangement = Arrangement.spacedBy(1)) {
Items(4)
}
Row(modifier, horizontalArrangement = Arrangement.Center) {
Items(3)
}
Row(modifier, horizontalArrangement = Arrangement.SpaceAround) {
Items(3)
}
Row(modifier, horizontalArrangement = Arrangement.SpaceBetween) {
Items(3)
}
// Item(Material.BLACK_STAINED_GLASS, modifier = Modifier.fillMaxHeight())
// Column {
// Item(Material.RED_CONCRETE, modifier = Modifier.fillMaxWidth().height(3).padding(1))
// Item(Material.BLUE_CONCRETE, modifier = Modifier.fillMaxSize().padding(1))
// }
}
}
}

@Composable
private fun Items(count: Int) {
repeat(count) {
Item(Material.RED_CONCRETE)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ import com.mineinabyss.guiy.components.Spacer
import com.mineinabyss.guiy.components.canvases.Chest
import com.mineinabyss.guiy.components.state.IntOffset
import com.mineinabyss.guiy.inventory.LocalGuiyOwner
import com.mineinabyss.guiy.jetpack.Alignment
import com.mineinabyss.guiy.layout.Box
import com.mineinabyss.guiy.layout.Row
import com.mineinabyss.guiy.layout.alignment.Alignment
import com.mineinabyss.guiy.modifiers.*
import com.mineinabyss.guiy.modifiers.Modifier
import com.mineinabyss.guiy.modifiers.click.clickable
import com.mineinabyss.guiy.modifiers.fillMaxSize
import com.mineinabyss.guiy.modifiers.height
import com.mineinabyss.guiy.modifiers.placement.absolute.at
import com.mineinabyss.guiy.modifiers.width
import org.bukkit.Material
import org.bukkit.entity.Player

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.runtime.*
import com.mineinabyss.guiy.components.Item
import com.mineinabyss.guiy.components.VerticalGrid
import com.mineinabyss.guiy.components.canvases.Chest
import com.mineinabyss.guiy.components.lists.NavbarPosition
import com.mineinabyss.guiy.components.lists.Paginated
import com.mineinabyss.guiy.inventory.LocalGuiyOwner
import com.mineinabyss.guiy.modifiers.Modifier
Expand All @@ -30,7 +31,7 @@ fun PaginatedMenu(player: Player) {
Paginated(
items,
page = page,
itemsPerPage = 9 * 5,
navbarPosition = NavbarPosition.START,
previousButton = { Item(Material.RED_CONCRETE, "Previous", modifier = Modifier.clickable { page-- }) },
nextButton = { Item(Material.BLUE_CONCRETE, "Next", modifier = Modifier.clickable { page++ }) },
) { pageItems ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,20 @@ fun CreativeItem(
) {
Item(itemStack, modifier.clickable {
// Mimic all vanilla interactions
val shiftClick = clickType == ClickType.SHIFT_LEFT || clickType == ClickType.SHIFT_RIGHT
val result: ItemStack? = when {
(shiftClick || clickType == ClickType.MIDDLE) && cursor == null -> itemStack?.clone()
?.apply { amount = maxStackSize }
(clickType.isShiftClick || clickType == ClickType.MIDDLE) && cursor == null ->
itemStack?.asQuantity(itemStack.maxStackSize)

clickType == ClickType.MIDDLE -> return@clickable

(clickType == ClickType.SHIFT_LEFT && cursor != null && cursor.isSimilar(itemStack)) ->
cursor.clone().apply { amount = maxStackSize }
clickType == ClickType.SHIFT_LEFT && cursor != null && cursor.isSimilar(itemStack) ->
cursor.asQuantity(cursor.maxStackSize)

cursor == null -> itemStack?.clone()?.apply { amount = 1 }
cursor == null -> itemStack?.clone()?.asOne()

clickType == ClickType.RIGHT || clickType == ClickType.SHIFT_RIGHT -> cursor.clone().subtract()
clickType.isRightClick -> cursor.clone().subtract()

(clickType == ClickType.LEFT || clickType == ClickType.SHIFT_LEFT) && !cursor.isSimilar(itemStack) -> null
clickType.isLeftClick && !cursor.isSimilar(itemStack) -> null

else -> cursor.clone().add()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ fun Chest(
content: @Composable () -> Unit,
) {
var size by remember { mutableStateOf(Size()) }
val constrainedModifier = modifier.sizeIn(CHEST_WIDTH, CHEST_WIDTH, MIN_CHEST_HEIGHT, MAX_CHEST_HEIGHT)
val constrainedModifier =
Modifier.sizeIn(CHEST_WIDTH, CHEST_WIDTH, MIN_CHEST_HEIGHT, MAX_CHEST_HEIGHT).then(modifier)
.onSizeChanged { if (size != it) size = it }

val holder = rememberInventoryHolder(viewers, onClose)
Expand Down
Loading
Loading