Skip to content

Commit

Permalink
Experimental implementation for #31
Browse files Browse the repository at this point in the history
Introduced a higher level wrapper for multi page screens with cramming options
  • Loading branch information
Matt-MX committed Jul 4, 2024
1 parent 947289b commit ac911d5
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.mattmx.ktgui.components.screen.pagination

import com.mattmx.ktgui.components.button.GuiButton
import com.mattmx.ktgui.components.screen.GuiScreen
import com.mattmx.ktgui.dsl.button
import com.mattmx.ktgui.utils.not
import net.kyori.adventure.text.Component
import org.bukkit.Material

class GuiCramMultiPageScreen(
title: Component,
rows: Int = 6
) : GuiMultiPageScreen(title, rows) {
val extraReservedSlots = arrayListOf<Int>()

infix fun reserve(slots: IntRange) = extraReservedSlots.addAll(slots)
infix fun reserve(slots: List<Int>) = extraReservedSlots.addAll(slots)

operator fun GuiButton<*>.unaryPlus() = cramAdd(this)
operator fun Collection<GuiButton<*>>.unaryPlus() = forEach { cramAdd(it) }
open fun cramAdd(child: GuiButton<*>) {
var lastPage = pages.lastOrNull()

// If it's full then make a new one
if (lastPage == null || isFull(lastPage)) {
lastPage = GuiScreen(Component.empty(), rows).apply { pages.add(this) }
}

val nextSlot = nextSlotToFill(lastPage)
if (nextSlot == null) {
GuiScreen(Component.empty(), rows).apply { pages.add(this) }
return cramAdd(child)
}

child childOf lastPage slot nextSlot
}

fun nextSlotToFill(sub: GuiScreen): Int? {
var nextSlot = sub.slotsUsed().max() + 1

while (nextSlot in reservedSlots() && nextSlot <= sub.totalSlots()) {
nextSlot++
}

if (nextSlot >= sub.totalSlots()) return null

return nextSlot
}

fun isFull(sub: GuiScreen) = sub.slotsUsed().size >= totalSlots() - reservedSlots().size

fun reservedSlots() = this.slotsUsed() + extraReservedSlots

}

fun cramMultiPageScreen(title: Component, rows: Int = 6, block: GuiCramMultiPageScreen.() -> Unit) =
GuiCramMultiPageScreen(title, rows).apply(block)

fun main() {
val gui = cramMultiPageScreen(!"Materials") {
reserve(last() - 8..last())

button(Material.SPECTRAL_ARROW) {
named(!"&aNext")
click.left { navigateNextPage() }
} slot last()

button(Material.SPECTRAL_ARROW) {
named(!"&cLast")
click.left { navigatePreviousPage() }
} slot last() - 8

+Material.values().map { button(it) {} }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.mattmx.ktgui.components.screen.pagination

import com.mattmx.ktgui.components.screen.GuiScreen
import com.mattmx.ktgui.dsl.button
import com.mattmx.ktgui.event.EventCallback
import com.mattmx.ktgui.utils.not
import net.kyori.adventure.text.Component
import org.bukkit.Material
import java.util.*
import kotlin.math.max
import kotlin.math.min

open class GuiMultiPageScreen(
title: Component,
rows: Int = 6
) : GuiScreen(title, rows) {
var currentPage = 0
set(value) {
field = value
refresh()
pageChange.invoke(value)
}
val pageChange = EventCallback<Int>()
val pages = Collections.synchronizedList(arrayListOf<GuiScreen>())

infix fun page(block: GuiScreen.() -> Unit) = page(null, block)
open fun page(index: Int? = null, block: GuiScreen.() -> Unit) = apply {
val sub = GuiScreen(Component.empty(), rows).apply(block)
if (index == null) {
pages.add(sub)
} else {
pages[index] = sub
}
}

open fun navigatePreviousPage() {
currentPage = max(0, currentPage - 1)
}

open fun navigateNextPage() {
currentPage = min(pages.size, currentPage + 1)
}
}

fun multiPageGui(title: Component, rows: Int = 6, block: GuiMultiPageScreen.() -> Unit) =
GuiMultiPageScreen(title, rows).apply(block)

fun main() {
val gui = multiPageGui(!"Test") {
button(Material.SPECTRAL_ARROW) {
named(!"&aLast")
click.left { navigatePreviousPage() }
} slot last()

button(Material.SPECTRAL_ARROW) {
named(!"&aNext")
click.left { navigateNextPage() }
} slot last()

page {

}

page {

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ class Signal<V>(initial: V, private val owner: SignalOwner) : ReadWriteProperty<
*
* @return [value]
*/
operator fun invoke() = value.apply {
owner.addDependency(this@Signal)
operator fun SignalOwner.invoke() = value.apply {
addDependency(this@Signal)
}

fun get() = invoke()
fun SignalOwner.get() = invoke()

/**
* Set the value of [value].
Expand Down
2 changes: 1 addition & 1 deletion plugin/src/main/kotlin/com/mattmx/ktgui/KotlinGui.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class KotlinGui : JavaPlugin() {

val animatedScoreboard = AnimatedScoreboardExample()
val scoreboardExample = ScoreboardExample()
val signalScoreboardExample = SignalScoreboardExample()
val signalScoreboardExample = SignalScoreboardExample(this)
val examples = hashMapOf(
"animated-scoreboard" to { animatedScoreboard },
"scoreboard" to { scoreboardExample },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
package com.mattmx.ktgui.examples

import com.mattmx.ktgui.KotlinGui
import com.mattmx.ktgui.dsl.event
import com.mattmx.ktgui.scoreboards.dynamicScoreboard
import com.mattmx.ktgui.utils.not
import com.mattmx.ktgui.utils.placeholders
import com.mattmx.ktgui.utils.pretty
import com.mattmx.ktgui.utils.seconds
import net.kyori.adventure.text.Component
import org.bukkit.entity.Player
import org.bukkit.event.player.PlayerInteractEvent
import java.text.DateFormat
import java.util.*
import kotlin.math.max
import kotlin.math.min

class SignalScoreboardExample : Example {
class SignalScoreboardExample(
plugin: KotlinGui
) : Example {
// var timesDisplayed by signal(0)

init {
event<PlayerInteractEvent>(plugin) {
// timesDisplayed++
}
}

val board = dynamicScoreboard(!"&#3D7068&lYour Server") {

Expand Down

0 comments on commit ac911d5

Please sign in to comment.