Space compound update
This commit is contained in:
@@ -166,13 +166,40 @@ class InventoryGUIPageBuilder<T : ForInventory>(
|
|||||||
onClick: (clickEvent: InventoryGUIClickEvent<T>, element: E) -> Unit
|
onClick: (clickEvent: InventoryGUIClickEvent<T>, element: E) -> Unit
|
||||||
) = InventoryGUISpaceCompound(type, iconGenerator, onClick)
|
) = 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
|
* Defines an area where the content of the given compound
|
||||||
* is displayed.
|
* is displayed.
|
||||||
*/
|
*/
|
||||||
fun <E> compoundSpace(
|
fun <E> compoundSpace(
|
||||||
slots: InventorySlotCompound<T>,
|
slots: InventorySlotCompound<T>,
|
||||||
compound: InventoryGUISpaceCompound<T, E>
|
compound: AbstractInventoryGUISpaceCompound<T, E>
|
||||||
) {
|
) {
|
||||||
compound.addSlots(slots)
|
compound.addSlots(slots)
|
||||||
defineSlots(
|
defineSlots(
|
||||||
@@ -183,24 +210,45 @@ class InventoryGUIPageBuilder<T : ForInventory>(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* By pressing this button,
|
* 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>,
|
slots: InventorySlotCompound<T>,
|
||||||
icon: ItemStack,
|
icon: ItemStack,
|
||||||
compound: InventoryGUISpaceCompound<T, *>,
|
compound: InventoryGUISpaceCompound<T, *>,
|
||||||
scrollDistance: Int = compound.invType.dimensions.height
|
scrollDistance: Int = 1,
|
||||||
) = defineSlots(slots, InventoryGUISpaceCompoundScrollButton(icon, compound, scrollDistance.absoluteValue))
|
scrollTimes: Int = 1,
|
||||||
|
reverse: Boolean = false
|
||||||
|
) = defineSlots(
|
||||||
|
slots,
|
||||||
|
InventoryGUISpaceCompoundScrollButton(
|
||||||
|
icon,
|
||||||
|
compound,
|
||||||
|
scrollDistance.absoluteValue,
|
||||||
|
scrollTimes,
|
||||||
|
reverse
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By pressing this button,
|
* 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>,
|
slots: InventorySlotCompound<T>,
|
||||||
icon: ItemStack,
|
icon: ItemStack,
|
||||||
compound: InventoryGUISpaceCompound<T, *>,
|
compound: InventoryGUIRectSpaceCompound<T, *>,
|
||||||
scrollDistance: Int = compound.invType.dimensions.height
|
scrollTimes: Int = 1,
|
||||||
) = defineSlots(slots, InventoryGUISpaceCompoundScrollButton(icon, compound, -scrollDistance.absoluteValue))
|
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
|
package net.axay.kspigot.inventory.elements
|
||||||
|
|
||||||
import net.axay.kspigot.inventory.ForInventory
|
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 net.axay.kspigot.runnables.task
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
|
||||||
class InventoryGUISpaceCompoundScrollButton<T : ForInventory>(
|
class InventoryGUISpaceCompoundScrollButton<T : ForInventory>(
|
||||||
private val icon: ItemStack,
|
icon: ItemStack,
|
||||||
private val compound: InventoryGUISpaceCompound<T, *>,
|
private val compound: AbstractInventoryGUISpaceCompound<T, *>,
|
||||||
private val scrollDistance: Int = compound.invType.dimensions.height,
|
private val scrollDistance: Int,
|
||||||
|
private val scrollTimes: Int,
|
||||||
private val reverse: Boolean = false
|
private val reverse: Boolean = false
|
||||||
) : InventoryGUIElement<T>() {
|
) : InventoryGUIButton<T>(icon, {
|
||||||
|
if (scrollTimes > 1) {
|
||||||
override fun getItemStack(slot: Int) = icon
|
|
||||||
|
|
||||||
override fun onClickElement(clickEvent: InventoryGUIClickEvent<T>) {
|
|
||||||
task(
|
task(
|
||||||
period = 1,
|
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()
|
if (!ifScrolled) it.cancel()
|
||||||
}
|
}
|
||||||
}
|
} else if (scrollTimes == 1)
|
||||||
|
if (reverse) compound.scroll(-scrollDistance) else compound.scroll(scrollDistance)
|
||||||
}
|
})
|
Reference in New Issue
Block a user