Skip to content

Commit

Permalink
Layout modifiers (#10)
Browse files Browse the repository at this point in the history
* fix: Fix row and column placement not accumulating width/height respectively
feat: Add layout modifiers that can alter placement and measurement
feat: Add padding modifier
feat: Add offset modifier

* fix: fold Modifiers in instead of out (the expected left takes precedence over right behaviour)
fix: First size always wins
fix: Make padding behaviour consistent with Jetpack Compose's
fix: Accidental double then() on some extensions calling other extensions
refactor: modifyLayoutConstraints runs after inner constraints have been calculated and element measure

* refactor: cleanup CreativeItem

* refactor: allow for customized navbarFiller item

* fix: fill paginated-content after navbar

* feat: Row and Column arrangement from jetpack
refactor: Cleanup Paginated component to space things automatically

* chore: Update readme

* fix: Fix building PRs with java 17

---------

Co-authored-by: Boy <[email protected]>
  • Loading branch information
0ffz and Boy0000 authored Jun 3, 2024
1 parent 7cfd0bd commit 4fc09f1
Show file tree
Hide file tree
Showing 31 changed files with 1,343 additions and 187 deletions.
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
15 changes: 7 additions & 8 deletions src/main/kotlin/com/mineinabyss/guiy/components/CreativeItem.kt
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

0 comments on commit 4fc09f1

Please sign in to comment.