Space compound update
This commit is contained in:
@@ -166,13 +166,40 @@ class InventoryGUIPageBuilder<T : ForInventory>(
|
||||
onClick: (clickEvent: InventoryGUIClickEvent<T>, element: E) -> Unit
|
||||
) = InventoryGUISpaceCompound(type, iconGenerator, onClick)
|
||||
|
||||
/**
|
||||
* Creates a new compound, holding data which can be displayed
|
||||
* in any compound space.
|
||||
* This compound is strictly a rectangle.
|
||||
* The space is automatically defined.
|
||||
*/
|
||||
fun <E> createCompound(
|
||||
fromSlot: SingleInventorySlot<out T>,
|
||||
toSlot: SingleInventorySlot<out T>,
|
||||
iconGenerator: (E) -> ItemStack,
|
||||
onClick: (clickEvent: InventoryGUIClickEvent<T>, element: E) -> Unit
|
||||
): InventoryGUIRectSpaceCompound<T, E> {
|
||||
val rectSlotCompound = fromSlot rectTo toSlot
|
||||
return InventoryGUIRectSpaceCompound(
|
||||
type,
|
||||
iconGenerator,
|
||||
onClick,
|
||||
(rectSlotCompound.endInclusive.slotInRow - rectSlotCompound.start.slotInRow) + 1
|
||||
).apply {
|
||||
addSlots(rectSlotCompound)
|
||||
defineSlots(
|
||||
rectSlotCompound,
|
||||
InventoryGUISpaceCompoundElement(this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an area where the content of the given compound
|
||||
* is displayed.
|
||||
*/
|
||||
fun <E> compoundSpace(
|
||||
slots: InventorySlotCompound<T>,
|
||||
compound: InventoryGUISpaceCompound<T, E>
|
||||
compound: AbstractInventoryGUISpaceCompound<T, E>
|
||||
) {
|
||||
compound.addSlots(slots)
|
||||
defineSlots(
|
||||
@@ -183,24 +210,45 @@ class InventoryGUIPageBuilder<T : ForInventory>(
|
||||
|
||||
/**
|
||||
* By pressing this button,
|
||||
* the user scrolls forward in the compound.
|
||||
* the user scrolls forwards or backwards in the compound.
|
||||
*/
|
||||
fun compoundScrollForwards(
|
||||
fun compoundScroll(
|
||||
slots: InventorySlotCompound<T>,
|
||||
icon: ItemStack,
|
||||
compound: InventoryGUISpaceCompound<T, *>,
|
||||
scrollDistance: Int = compound.invType.dimensions.height
|
||||
) = defineSlots(slots, InventoryGUISpaceCompoundScrollButton(icon, compound, scrollDistance.absoluteValue))
|
||||
scrollDistance: Int = 1,
|
||||
scrollTimes: Int = 1,
|
||||
reverse: Boolean = false
|
||||
) = defineSlots(
|
||||
slots,
|
||||
InventoryGUISpaceCompoundScrollButton(
|
||||
icon,
|
||||
compound,
|
||||
scrollDistance.absoluteValue,
|
||||
scrollTimes,
|
||||
reverse
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* By pressing this button,
|
||||
* the user scrolls backwards in the compound.
|
||||
* the user scrolls forwards or backwards in the compound.
|
||||
*/
|
||||
fun compoundScrollBackwards(
|
||||
fun compoundScroll(
|
||||
slots: InventorySlotCompound<T>,
|
||||
icon: ItemStack,
|
||||
compound: InventoryGUISpaceCompound<T, *>,
|
||||
scrollDistance: Int = compound.invType.dimensions.height
|
||||
) = defineSlots(slots, InventoryGUISpaceCompoundScrollButton(icon, compound, -scrollDistance.absoluteValue))
|
||||
compound: InventoryGUIRectSpaceCompound<T, *>,
|
||||
scrollTimes: Int = 1,
|
||||
reverse: Boolean = false
|
||||
) = defineSlots(
|
||||
slots,
|
||||
InventoryGUISpaceCompoundScrollButton(
|
||||
icon,
|
||||
compound,
|
||||
compound.compoundWidth,
|
||||
scrollTimes,
|
||||
reverse
|
||||
)
|
||||
)
|
||||
|
||||
}
|
@@ -0,0 +1,166 @@
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package net.axay.kspigot.inventory.elements
|
||||
|
||||
import net.axay.kspigot.inventory.*
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
class InventoryGUISpaceCompoundElement<T : ForInventory, E> internal constructor(
|
||||
private val compound: AbstractInventoryGUISpaceCompound<T, E>
|
||||
) : InventoryGUIElement<T>() {
|
||||
|
||||
override fun getItemStack(slot: Int) = compound.getItemStack(slot)
|
||||
|
||||
override fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) {
|
||||
compound.onClickElement(clickEvent)
|
||||
}
|
||||
|
||||
override fun startUsing(gui: InventoryGUI<*>) = compound.registerGUI(gui)
|
||||
|
||||
override fun stopUsing(gui: InventoryGUI<*>) = compound.unregisterGUI(gui)
|
||||
|
||||
}
|
||||
|
||||
class InventoryGUIRectSpaceCompound<T : ForInventory, E>(
|
||||
invType: InventoryType<T>,
|
||||
iconGenerator: (E) -> ItemStack,
|
||||
onClick: (InventoryGUIClickEvent<T>, E) -> Unit,
|
||||
internal val compoundWidth: Int
|
||||
) : AbstractInventoryGUISpaceCompound<T, E>(invType, iconGenerator, onClick) {
|
||||
|
||||
override fun handleScrollEndReached(newProgress: Int, internalSlotsSize: Int, contentSize: Int) =
|
||||
(internalSlotsSize + newProgress <= contentSize + (compoundWidth - (contentSize % compoundWidth)))
|
||||
|
||||
}
|
||||
|
||||
class InventoryGUISpaceCompound<T : ForInventory, E>(
|
||||
invType: InventoryType<T>,
|
||||
iconGenerator: (E) -> ItemStack,
|
||||
onClick: (InventoryGUIClickEvent<T>, E) -> Unit
|
||||
) : AbstractInventoryGUISpaceCompound<T, E>(invType, iconGenerator, onClick) {
|
||||
|
||||
override fun handleScrollEndReached(newProgress: Int, internalSlotsSize: Int, contentSize: Int) = false
|
||||
|
||||
}
|
||||
|
||||
abstract class AbstractInventoryGUISpaceCompound<T : ForInventory, E> internal constructor(
|
||||
val invType: InventoryType<T>,
|
||||
private val iconGenerator: (E) -> ItemStack,
|
||||
private val onClick: (InventoryGUIClickEvent<T>, E) -> Unit
|
||||
) {
|
||||
|
||||
private val content = ArrayList<E>()
|
||||
private var currentContent: List<E> = emptyList()
|
||||
|
||||
private val internalSlots: MutableList<Int> = ArrayList()
|
||||
|
||||
private var scrollProgress: Int = 0
|
||||
|
||||
private var contentSort: () -> Unit = { }
|
||||
|
||||
private val registeredGUIs = HashSet<InventoryGUI<*>>()
|
||||
|
||||
private fun contentAtSlot(slot: Int) = currentContent.getOrNull(internalSlots.indexOf(slot))
|
||||
|
||||
private fun recalculateCurrentContent() {
|
||||
|
||||
if (scrollProgress >= content.size)
|
||||
throw IllegalStateException("The scrollProgress is greater than the content size.")
|
||||
|
||||
// avoid IndexOutOfBoundsException
|
||||
var sliceUntil = internalSlots.size + scrollProgress
|
||||
if (sliceUntil > content.lastIndex)
|
||||
sliceUntil = content.size
|
||||
|
||||
currentContent = content.slice(scrollProgress until sliceUntil)
|
||||
|
||||
}
|
||||
|
||||
private fun updateOpenGUIs() {
|
||||
registeredGUIs.forEach { it.reloadCurrentPage() }
|
||||
}
|
||||
|
||||
internal fun scroll(distance: Int): Boolean {
|
||||
val value = scrollProgress + distance
|
||||
return if (value >= 0) {
|
||||
|
||||
// always scroll if the end of the content is not reached
|
||||
val ifScroll = if (internalSlots.size + value <= content.size) true
|
||||
// scroll further if the width of the compound is defined and the last line can be filled up
|
||||
else handleScrollEndReached(value, internalSlots.size, content.size)
|
||||
|
||||
if (ifScroll) {
|
||||
scrollProgress = value
|
||||
recalculateCurrentContent()
|
||||
updateOpenGUIs()
|
||||
true
|
||||
} else false
|
||||
|
||||
} else false
|
||||
}
|
||||
|
||||
internal abstract fun handleScrollEndReached(newProgress: Int, internalSlotsSize: Int, contentSize: Int): Boolean
|
||||
|
||||
internal fun getItemStack(slot: Int): ItemStack {
|
||||
return contentAtSlot(slot)?.let { return@let iconGenerator.invoke(it) }
|
||||
?: ItemStack(Material.AIR)
|
||||
}
|
||||
|
||||
internal fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) {
|
||||
val element = contentAtSlot(clickEvent.bukkitEvent.slot) ?: kotlin.run {
|
||||
clickEvent.bukkitEvent.isCancelled = true
|
||||
return
|
||||
}
|
||||
onClick.invoke(clickEvent, element)
|
||||
}
|
||||
|
||||
internal fun addSlots(slots: InventorySlotCompound<T>) {
|
||||
slots.realSlotsWithInvType(invType).forEach {
|
||||
if (!internalSlots.contains(it))
|
||||
internalSlots.add(it)
|
||||
}
|
||||
internalSlots.sort()
|
||||
}
|
||||
|
||||
internal fun registerGUI(gui: InventoryGUI<*>) {
|
||||
registeredGUIs += gui
|
||||
}
|
||||
|
||||
internal fun unregisterGUI(gui: InventoryGUI<*>) {
|
||||
registeredGUIs -= gui
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the sort behaviour which gets applied to the content
|
||||
* automatically.
|
||||
*/
|
||||
fun <R : Comparable<R>> sortContentBy(reverse: Boolean = false, selector: (E) -> R?) {
|
||||
contentSort = {
|
||||
if (!reverse) content.sortBy(selector) else content.sortByDescending(selector)
|
||||
}
|
||||
contentSort.invoke()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new element to the compound.
|
||||
*/
|
||||
fun addContent(element: E) {
|
||||
addContent(listOf(element))
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new elements to the compound.
|
||||
*/
|
||||
fun addContent(elements: Collection<E>) {
|
||||
|
||||
content += elements
|
||||
contentSort.invoke()
|
||||
|
||||
recalculateCurrentContent()
|
||||
|
||||
updateOpenGUIs()
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,131 +0,0 @@
|
||||
@file:Suppress("MemberVisibilityCanBePrivate", "unused")
|
||||
|
||||
package net.axay.kspigot.inventory.elements
|
||||
|
||||
import net.axay.kspigot.inventory.*
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
class InventoryGUISpaceCompoundElement<T : ForInventory, E> internal constructor(
|
||||
private val compound: InventoryGUISpaceCompound<T, E>
|
||||
) : InventoryGUIElement<T>() {
|
||||
|
||||
override fun getItemStack(slot: Int) = compound.getItemStack(slot)
|
||||
|
||||
override fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) {
|
||||
compound.onClickElement(clickEvent)
|
||||
}
|
||||
|
||||
override fun startUsing(gui: InventoryGUI<*>) = compound.registerGUI(gui)
|
||||
|
||||
override fun stopUsing(gui: InventoryGUI<*>) = compound.unregisterGUI(gui)
|
||||
|
||||
}
|
||||
|
||||
class InventoryGUISpaceCompound<T : ForInventory, E>(
|
||||
val invType: InventoryType<T>,
|
||||
private val iconGenerator: (E) -> ItemStack,
|
||||
private val onClick: (InventoryGUIClickEvent<T>, E) -> Unit
|
||||
) {
|
||||
|
||||
private val content = ArrayList<E>()
|
||||
|
||||
private val realInternalSlots = ArrayList<Int>()
|
||||
|
||||
private val currentInternalSlots: List<Int>
|
||||
get() {
|
||||
|
||||
val result = ArrayList(realInternalSlots)
|
||||
|
||||
var more = 1
|
||||
while (content.size > result.size) {
|
||||
result += realInternalSlots.mapTo(ArrayList()) { it + (more * invType.dimensions.slotAmount) }
|
||||
more++
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
internal var scrolledLines: Int = 0; private set
|
||||
|
||||
fun scroll(distance: Int): Boolean {
|
||||
val value = scrolledLines + distance
|
||||
return if (
|
||||
value >= 0 &&
|
||||
((value - 1) * invType.dimensions.width) < content.size
|
||||
) {
|
||||
scrolledLines = value
|
||||
onChange()
|
||||
true
|
||||
} else false
|
||||
}
|
||||
|
||||
private var contentSort: () -> Unit = { }
|
||||
|
||||
private val registeredGUIs = HashSet<InventoryGUI<*>>()
|
||||
|
||||
private fun translateSlot(slot: Int) = (scrolledLines * invType.dimensions.width) + slot
|
||||
|
||||
private fun contentAtSlot(slot: Int) = content.getOrNull(
|
||||
realInternalSlots.indexOf(translateSlot(slot))
|
||||
)
|
||||
|
||||
internal fun getItemStack(slot: Int): ItemStack {
|
||||
return contentAtSlot(slot)?.let { return@let iconGenerator.invoke(it) }
|
||||
?: ItemStack(Material.AIR)
|
||||
}
|
||||
|
||||
internal fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) {
|
||||
val element = contentAtSlot(clickEvent.bukkitEvent.slot) ?: return
|
||||
onClick.invoke(clickEvent, element)
|
||||
}
|
||||
|
||||
internal fun addSlots(slots: InventorySlotCompound<T>) {
|
||||
slots.realSlotsWithInvType(invType).forEach {
|
||||
if (!realInternalSlots.contains(it))
|
||||
realInternalSlots.add(it)
|
||||
}
|
||||
realInternalSlots.sort()
|
||||
}
|
||||
|
||||
internal fun onChange() {
|
||||
registeredGUIs.forEach { it.reloadCurrentPage() }
|
||||
}
|
||||
|
||||
internal fun registerGUI(gui: InventoryGUI<*>) {
|
||||
registeredGUIs += gui
|
||||
}
|
||||
|
||||
internal fun unregisterGUI(gui: InventoryGUI<*>) {
|
||||
registeredGUIs -= gui
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the sort behaviour which gets applied to the content
|
||||
* automatically.
|
||||
*/
|
||||
fun <R : Comparable<R>> sortContentBy(reverse: Boolean = false, selector: (E) -> R?) {
|
||||
contentSort = {
|
||||
if (!reverse) content.sortBy(selector) else content.sortByDescending(selector)
|
||||
}
|
||||
contentSort.invoke()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new element to the compound.
|
||||
*/
|
||||
fun addContent(element: E) {
|
||||
addContent(listOf(element))
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new elements to the compound.
|
||||
*/
|
||||
fun addContent(elements: Collection<E>) {
|
||||
content += elements
|
||||
contentSort.invoke()
|
||||
onChange()
|
||||
}
|
||||
|
||||
}
|
@@ -1,28 +1,24 @@
|
||||
package net.axay.kspigot.inventory.elements
|
||||
|
||||
import net.axay.kspigot.inventory.ForInventory
|
||||
import net.axay.kspigot.inventory.InventoryGUIClickEvent
|
||||
import net.axay.kspigot.inventory.InventoryGUIElement
|
||||
import net.axay.kspigot.runnables.task
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
class InventoryGUISpaceCompoundScrollButton<T : ForInventory>(
|
||||
private val icon: ItemStack,
|
||||
private val compound: InventoryGUISpaceCompound<T, *>,
|
||||
private val scrollDistance: Int = compound.invType.dimensions.height,
|
||||
icon: ItemStack,
|
||||
private val compound: AbstractInventoryGUISpaceCompound<T, *>,
|
||||
private val scrollDistance: Int,
|
||||
private val scrollTimes: Int,
|
||||
private val reverse: Boolean = false
|
||||
) : InventoryGUIElement<T>() {
|
||||
|
||||
override fun getItemStack(slot: Int) = icon
|
||||
|
||||
override fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) {
|
||||
) : InventoryGUIButton<T>(icon, {
|
||||
if (scrollTimes > 1) {
|
||||
task(
|
||||
period = 1,
|
||||
howOften = scrollDistance.toLong()
|
||||
howOften = scrollTimes.toLong()
|
||||
) {
|
||||
val ifScrolled = if (reverse) compound.scroll(-1) else compound.scroll(1)
|
||||
val ifScrolled = if (reverse) compound.scroll(-scrollDistance) else compound.scroll(scrollDistance)
|
||||
if (!ifScrolled) it.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else if (scrollTimes == 1)
|
||||
if (reverse) compound.scroll(-scrollDistance) else compound.scroll(scrollDistance)
|
||||
})
|
Reference in New Issue
Block a user