Quick search in pattern grid

This commit is contained in:
DBotThePony 2023-03-08 09:34:06 +07:00
parent 1315636948
commit dd74643c67
Signed by: DBot
GPG Key ID: DCC23B5715498507
6 changed files with 104 additions and 15 deletions

View File

@ -586,6 +586,8 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) {
with(provider.english) {
gui("quicksearch", "Quick search...")
gui("item_monitor.refill_source.desc", "Controls from where to take items for slot auto refill")
gui("item_monitor.refill_source.system", "System only. Crafting grid will be auto refilled only from storage system. This is the behavior you see in AE2 and Refined Storage")
gui("item_monitor.refill_source.inventory", "Inventory only. Crafting grid will be auto refilled only from player's inventory")

View File

@ -594,6 +594,8 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) {
with(provider.russian) {
gui("quicksearch", "Быстрый поиск...")
gui("item_monitor.refill_source.desc", "Контролирует источник предметов для заполнения сетки создания")
gui("item_monitor.refill_source.system", "Только система. Сетка создания будет заполняться только из системы предметов. Данный параметр соответствует поведению AE2 и Refined Storage")
gui("item_monitor.refill_source.inventory", "Только инвентарь. Сетка создания будет заполняться только из инвентаря игрока")

View File

@ -32,6 +32,7 @@ import ru.dbotthepony.mc.otm.menu.matter.MatterPanelMenu
import ru.dbotthepony.mc.otm.menu.matter.ReplicationRequestPacket
import ru.dbotthepony.mc.otm.network.MenuNetworkChannel
import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak
import java.util.function.Predicate
import kotlin.math.roundToInt
@MouseTweaksDisableWheelTweak
@ -45,7 +46,8 @@ class MatterPanelScreen(
var scrollPatterns = 0
var scrollTasks = 0
val frame = FramePanel.padded(this, null, GRID_WIDTH * AbstractSlotPanel.SIZE + ScrollBarConstants.WIDTH + 4f, GRID_HEIGHT * AbstractSlotPanel.SIZE, title)
val frame = FramePanel.padded(this, null, GRID_WIDTH * AbstractSlotPanel.SIZE + ScrollBarConstants.WIDTH + 4f, GRID_HEIGHT * AbstractSlotPanel.SIZE + 2f, title)
frame.dockPadding = frame.dockPadding.copy(top = frame.dockPadding.top + 2f)
val controls = DeviceControls(this, frame)
@ -69,9 +71,9 @@ class MatterPanelScreen(
val scrollBar = DiscreteScrollBarPanel(this, frame, {
if (isPatternView) {
integerDivisionDown(menu.patterns.size, GRID_WIDTH)
integerDivisionDown(menu.patternsFiltered.size, GRID_WIDTH)
} else {
integerDivisionDown(menu.tasks.size, GRID_WIDTH)
integerDivisionDown(menu.tasksFiltered.size, GRID_WIDTH)
}
}, { _, _, new ->
if (isPatternView)
@ -80,6 +82,25 @@ class MatterPanelScreen(
scrollTasks = new
})
object : TextInputPanel<MatterPanelScreen>(this@MatterPanelScreen, frame) {
init {
width = frame.width * 0.4f
x = frame.width - width - FramePanel.PADDING
y = 4f
placeholder = TranslatableComponent("otm.gui.quicksearch")
}
override fun onTextChanged(old: String, new: String) {
if (new == "") {
menu.filter = Predicate { true }
} else {
val new = new.lowercase()
menu.filter = Predicate { it.description.string.lowercase().contains(new) }
scrollBar.scroll = scrollBar.scroll
}
}
}
scrollBar.dock = Dock.RIGHT
frame.Tab(onOpen = { isPatternView = true; scrollBar.scroll = scrollPatterns }, activeIcon = PATTERN_LIST_ACTIVE, inactiveIcon = PATTERN_LIST_INACTIVE).also {
@ -121,9 +142,9 @@ class MatterPanelScreen(
override val itemStack: ItemStack get() {
if (isPatternView) {
return menu.patterns.getOrNull(index)?.stack() ?: ItemStack.EMPTY
return menu.patternsFiltered.getOrNull(index)?.stack() ?: ItemStack.EMPTY
} else {
return menu.tasks.getOrNull(index)?.let { it.stack(it.required + it.inProgress) } ?: ItemStack.EMPTY
return menu.tasksFiltered.getOrNull(index)?.let { it.stack(it.required + it.inProgress) } ?: ItemStack.EMPTY
}
}
@ -131,13 +152,13 @@ class MatterPanelScreen(
val list = super.getItemStackTooltip(stack).toMutableList()
if (isPatternView) {
menu.patterns.getOrNull(index)?.let {
menu.patternsFiltered.getOrNull(index)?.let {
list.add(TranslatableComponent(
"otm.item.pattern.research",
String.format("%.2f", it.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA)) }
} else {
menu.tasks.getOrNull(index)?.let {
menu.tasksFiltered.getOrNull(index)?.let {
list.add(TranslatableComponent("otm.gui.matter_task.total", it.total).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.required", it.required).withStyle(ChatFormatting.GRAY))
list.add(TranslatableComponent("otm.gui.matter_task.in_progress", it.inProgress).withStyle(ChatFormatting.GRAY))
@ -151,9 +172,9 @@ class MatterPanelScreen(
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
if (isPatternView) {
if (minecraft?.player?.isSpectator != true)
menu.patterns.getOrNull(index)?.let(this@MatterPanelScreen::openPattern)
menu.patternsFiltered.getOrNull(index)?.let(this@MatterPanelScreen::openPattern)
} else {
menu.tasks.getOrNull(index)?.let(this@MatterPanelScreen::openTask)
menu.tasksFiltered.getOrNull(index)?.let(this@MatterPanelScreen::openTask)
}
return true
@ -180,13 +201,13 @@ class MatterPanelScreen(
}
override val itemStack: ItemStack get() {
return menu.tasks.firstOrNull { it.id == task.id }?.let { it.stack((it.required + it.inProgress).coerceAtLeast(1)) } ?: task.stack((task.required + task.inProgress).coerceAtLeast(1))
return menu.tasksFiltered.firstOrNull { it.id == task.id }?.let { it.stack((it.required + it.inProgress).coerceAtLeast(1)) } ?: task.stack((task.required + task.inProgress).coerceAtLeast(1))
}
override fun tickInner() {
super.tickInner()
if (!menu.tasks.any { it.id == task.id }) {
if (!menu.tasksFiltered.any { it.id == task.id }) {
frame.remove()
}
}
@ -254,7 +275,7 @@ class MatterPanelScreen(
override fun tickInner() {
super.tickInner()
if (!menu.patterns.any { it.id == pattern.id }) {
if (!menu.patternsFiltered.any { it.id == pattern.id }) {
frame.remove()
}
}

View File

@ -12,6 +12,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.ints.Int2ObjectMap
import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.network.chat.Component
import org.joml.Vector2i
import ru.dbotthepony.mc.otm.client.isCtrlDown
import ru.dbotthepony.mc.otm.client.isShiftDown
@ -24,6 +25,7 @@ import ru.dbotthepony.mc.otm.client.render.drawRect
import ru.dbotthepony.mc.otm.client.render.tesselator
import ru.dbotthepony.mc.otm.client.screen.panels.DockProperty
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.addAll
import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.milliTime
@ -141,7 +143,9 @@ open class TextInputPanel<out S : Screen>(
var cursorLine = 0
var cursorRow = 0
open var placeholder: Component = TextComponent("")
open var textColor = RGBAColor.WHITE
open var placeholderColor = RGBAColor.DARK_GRAY
open var cursorColor = RGBAColor.GREEN
open var backgroundColor = RGBAColor.BLACK
open var isActive = true
@ -1085,6 +1089,18 @@ open class TextInputPanel<out S : Screen>(
var y = topPadding
if (lines.isEmpty() || lines.size == 1 && lines[0] == "") {
font.drawAligned(
poseStack = stack,
buffer = BUFFER,
text = placeholder,
align = TextAlign.TOP_LEFT,
x = dockPadding.left,
y = y,
color = placeholderColor
)
}
for (i in scrollLines until lines.size) {
val line = lines[i]
val selection = selections[i]

View File

@ -109,7 +109,7 @@ open class DiscreteScrollBarPanel<out S : Screen>(
var scroll = 0
set(value) {
val newValue = value.coerceAtLeast(0).coerceAtMost(maxScroll.invoke(this))
val newValue = value.coerceIn(0, maxScroll.invoke(this))
if (newValue != field) {
val old = field

View File

@ -4,6 +4,7 @@ import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor
import org.apache.logging.log4j.LogManager
@ -23,6 +24,7 @@ import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.network.*
import ru.dbotthepony.mc.otm.registry.MMenus
import java.util.*
import java.util.function.Predicate
import java.util.function.Supplier
import kotlin.Comparator
import kotlin.collections.ArrayList
@ -158,7 +160,9 @@ class MatterPanelMenu @JvmOverloads constructor(
codec = ItemSorter::class.codec(),
observer = {
patterns.sortWith(actualComparator)
patternsFiltered.sortWith(actualComparator)
tasks.sortWith(actualTaskComparator)
tasksFiltered.sortWith(actualTaskComparator)
})
val isAscending: Boolean by mSynchronizer.ComputedField(
@ -166,7 +170,9 @@ class MatterPanelMenu @JvmOverloads constructor(
codec = BooleanValueCodec,
observer = {
patterns.sortWith(actualComparator)
patternsFiltered.sortWith(actualComparator)
tasks.sortWith(actualTaskComparator)
tasksFiltered.sortWith(actualTaskComparator)
})
val totalMatterStored: Decimal by mSynchronizer.ComputedField(
@ -174,6 +180,25 @@ class MatterPanelMenu @JvmOverloads constructor(
codec = DecimalValueCodec,
)
var filter: Predicate<Item> = Predicate { true }
set(value) {
field = value
patternsFiltered.clear()
tasksFiltered.clear()
for (pattern in patterns) {
if (value.test(pattern.item)) {
patternsFiltered.add(pattern)
}
}
for (task in tasks) {
if (value.test(task.item)) {
tasksFiltered.add(task)
}
}
}
val changeIsAscending = booleanInput(allowSpectators = true) { tile?.getPlayerSettings(ply)?.ascending = it }
val changeSorting = PlayerInput(ItemSorter::class.codec(), allowSpectators = true) { tile?.getPlayerSettings(ply)?.sorter = it }
@ -183,8 +208,11 @@ class MatterPanelMenu @JvmOverloads constructor(
private val actualComparator = Comparator<IPatternState> { o1, o2 -> sorting.comparator.compare(o1.item, o2.item) * (if (isAscending) 1 else -1) }
private val actualTaskComparator = Comparator<IReplicationTask<*>> { o1, o2 -> sorting.comparator.compare(o1.item, o2.item) * (if (isAscending) 1 else -1) }
val patterns = ArrayList<IPatternState>()
val tasks = ArrayList<IReplicationTask<*>>()
private val patterns = ArrayList<IPatternState>()
private val tasks = ArrayList<IReplicationTask<*>>()
val patternsFiltered = ArrayList<IPatternState>()
val tasksFiltered = ArrayList<IReplicationTask<*>>()
fun networkPatternsUpdated(patterns: Collection<IPatternState>) {
for (pattern in patterns) {
@ -195,6 +223,16 @@ class MatterPanelMenu @JvmOverloads constructor(
} else {
this.patterns.addSorted(pattern, actualComparator)
}
if (filter.test(pattern.item)) {
val index = this.patternsFiltered.indexOfFirst(pattern::matchId)
if (index != -1) {
this.patternsFiltered[index] = pattern
} else {
this.patternsFiltered.addSorted(pattern, actualComparator)
}
}
}
}
@ -213,6 +251,16 @@ class MatterPanelMenu @JvmOverloads constructor(
} else {
this.tasks.addSorted(task, actualTaskComparator)
}
if (filter.test(task.item)) {
val index = this.tasksFiltered.indexOfFirst(task::matchId)
if (index != -1) {
this.tasksFiltered[index] = task
} else {
this.tasksFiltered.addSorted(task, actualTaskComparator)
}
}
}
}