Add interface priority syncing
This commit is contained in:
parent
385e36918f
commit
f321b2a06a
|
@ -10,6 +10,7 @@ import net.shadowfacts.cacao.geometry.Point
|
|||
import net.shadowfacts.cacao.geometry.Size
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.util.RenderHelper
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* A simple View that displays text. Allows for controlling the color and shadow of the text. Label cannot be used
|
||||
|
@ -26,10 +27,10 @@ import net.shadowfacts.cacao.util.RenderHelper
|
|||
*/
|
||||
class Label(
|
||||
text: Text,
|
||||
val shadow: Boolean = false,
|
||||
var shadow: Boolean = false,
|
||||
val maxLines: Int = 0,
|
||||
val wrappingMode: WrappingMode = WrappingMode.WRAP,
|
||||
val textAlignment: TextAlignment = TextAlignment.LEFT
|
||||
var textAlignment: TextAlignment = TextAlignment.LEFT
|
||||
): View() {
|
||||
|
||||
companion object {
|
||||
|
@ -59,7 +60,8 @@ class Label(
|
|||
var text: Text = text
|
||||
set(value) {
|
||||
field = value
|
||||
updateIntrinsicContentSize()
|
||||
// todo: uhhhh
|
||||
updateIntrinsicContentSize(true)
|
||||
// todo: setNeedsLayout instead of force unwrapping window
|
||||
window!!.layout()
|
||||
}
|
||||
|
@ -75,15 +77,23 @@ class Label(
|
|||
override fun wasAdded() {
|
||||
super.wasAdded()
|
||||
|
||||
updateIntrinsicContentSize()
|
||||
updateIntrinsicContentSize(false)
|
||||
}
|
||||
|
||||
private fun updateIntrinsicContentSize() {
|
||||
if (RenderHelper.disabled) return
|
||||
private fun updateIntrinsicContentSize(canWrap: Boolean): Boolean {
|
||||
if (RenderHelper.disabled) return false
|
||||
|
||||
val width = textRenderer.getWidth(text)
|
||||
val height = textRenderer.fontHeight
|
||||
intrinsicContentSize = Size(width.toDouble(), height.toDouble())
|
||||
val oldSize = intrinsicContentSize
|
||||
if (wrappingMode == WrappingMode.WRAP && canWrap) {
|
||||
val lines = textRenderer.wrapLines(text, bounds.width.toInt())
|
||||
val height = (if (maxLines == 0) lines.size else min(lines.size, maxLines)) * textRenderer.fontHeight
|
||||
intrinsicContentSize = Size(bounds.width, height.toDouble())
|
||||
} else {
|
||||
val width = textRenderer.getWidth(text)
|
||||
val height = textRenderer.fontHeight
|
||||
intrinsicContentSize = Size(width.toDouble(), height.toDouble())
|
||||
}
|
||||
return oldSize != intrinsicContentSize
|
||||
}
|
||||
|
||||
override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
||||
|
@ -110,14 +120,22 @@ class Label(
|
|||
super.didLayout()
|
||||
|
||||
computeLines()
|
||||
if (updateIntrinsicContentSize(true)) {
|
||||
// if the intrinsic content size changes, relayout
|
||||
window!!.layout()
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeLines() {
|
||||
var lines = textRenderer.wrapLines(text, bounds.width.toInt())
|
||||
if (maxLines > 0 && maxLines < lines.size) {
|
||||
lines = lines.dropLast(lines.size - maxLines)
|
||||
if (wrappingMode == WrappingMode.WRAP) {
|
||||
var lines = textRenderer.wrapLines(text, bounds.width.toInt())
|
||||
if (maxLines > 0 && maxLines < lines.size) {
|
||||
lines = lines.dropLast(lines.size - maxLines)
|
||||
}
|
||||
this.lines = lines
|
||||
} else {
|
||||
this.lines = listOf(text.asOrderedText())
|
||||
}
|
||||
this.lines = lines
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ open class View(): Responder {
|
|||
* The intrinsic size of this view's content. May be null if the view doesn't have any content or there is no
|
||||
* intrinsic size.
|
||||
*
|
||||
* Setting this creates/updates [no.birkett.kiwi.Strength.WEAK] constraints on this view's width/height using
|
||||
* Setting this creates/updates [no.birkett.kiwi.Strength.MEDIUM] constraints on this view's width/height using
|
||||
* the size.
|
||||
*/
|
||||
var intrinsicContentSize: Size? = null
|
||||
|
|
|
@ -1,25 +1,31 @@
|
|||
package net.shadowfacts.cacao.view.button
|
||||
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.geometry.Size
|
||||
import net.shadowfacts.cacao.util.MouseButton
|
||||
import net.shadowfacts.cacao.util.texture.Texture
|
||||
import net.shadowfacts.cacao.view.TextureView
|
||||
import net.shadowfacts.cacao.view.View
|
||||
|
||||
/**
|
||||
* A button for toggling between on/off states.
|
||||
*
|
||||
* @author shadowfacts
|
||||
* @param initialState Whether the button starts as on or off.
|
||||
* @param handler The handler function to invoke when this button is pressed.
|
||||
*/
|
||||
class ToggleButton(initialState: Boolean): AbstractButton<ToggleButton>(TextureView(if (initialState) ON else OFF).apply {
|
||||
intrinsicContentSize = Size(19.0, 19.0)
|
||||
}, padding = 0.0) {
|
||||
class ToggleButton(
|
||||
initialState: Boolean,
|
||||
handler: ((ToggleButton) -> Unit)? = null,
|
||||
): AbstractButton<ToggleButton>(TextureView(if (initialState) ON else OFF), padding = 0.0) {
|
||||
|
||||
companion object {
|
||||
val ON = Texture(Identifier("asmr", "textures/gui/toggle.png"), 0, 0)
|
||||
val OFF = Texture(Identifier("asmr", "textures/gui/toggle.png"), 0, 19)
|
||||
val OFF = Texture(Identifier("textures/gui/checkbox.png"), 0, 0, 64, 64)
|
||||
val OFF_HOVERED = Texture(Identifier("textures/gui/checkbox.png"), 20, 0, 64, 64)
|
||||
val ON = Texture(Identifier("textures/gui/checkbox.png"), 0, 20, 64, 64)
|
||||
val ON_HOVERED = Texture(Identifier("textures/gui/checkbox.png"), 20, 20, 64, 64)
|
||||
}
|
||||
|
||||
private val textureView: TextureView
|
||||
|
@ -30,10 +36,15 @@ class ToggleButton(initialState: Boolean): AbstractButton<ToggleButton>(TextureV
|
|||
* Updating this property updates the button's texture.
|
||||
*/
|
||||
var state: Boolean = initialState
|
||||
set(value) {
|
||||
field = value
|
||||
textureView.texture = if (value) ON else OFF
|
||||
}
|
||||
|
||||
init {
|
||||
this.handler = handler
|
||||
intrinsicContentSize = Size(20.0, 20.0)
|
||||
|
||||
background = null
|
||||
disabledBackground = null
|
||||
hoveredBackground = null
|
||||
}
|
||||
|
||||
override fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
|
||||
if (!disabled && (mouseButton == MouseButton.LEFT || mouseButton == MouseButton.RIGHT)) {
|
||||
|
@ -43,4 +54,17 @@ class ToggleButton(initialState: Boolean): AbstractButton<ToggleButton>(TextureV
|
|||
return super.mouseClicked(point, mouseButton)
|
||||
}
|
||||
|
||||
override fun draw(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
||||
val hovered = mouse in bounds
|
||||
textureView.texture = if (state) {
|
||||
if (hovered) ON_HOVERED else ON
|
||||
} else {
|
||||
if (hovered) OFF_HOVERED else OFF
|
||||
}
|
||||
|
||||
super.draw(matrixStack, mouse, delta)
|
||||
}
|
||||
|
||||
override fun getCurrentBackground(mouse: Point) = null
|
||||
|
||||
}
|
|
@ -97,6 +97,7 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
|
||||
private lateinit var outerStack: StackView
|
||||
private lateinit var tabStack: StackView
|
||||
private lateinit var currentTabController: ViewController
|
||||
// todo: this shouldn't be public, use layout guides
|
||||
lateinit var tabVCContainer: View
|
||||
private set
|
||||
|
@ -121,7 +122,11 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
tabVCContainer.zIndex = 1.0
|
||||
view.addSubview(tabVCContainer)
|
||||
|
||||
embedChild(currentTab.controller, tabVCContainer)
|
||||
currentTabController = currentTab.controller
|
||||
currentTabController.willMoveTo(this)
|
||||
embedChild(currentTabController, tabVCContainer)
|
||||
currentTabController.didMoveTo(this)
|
||||
// will/did appear events for the initial VC are provided by this class' implementations of those
|
||||
|
||||
view.solver.dsl {
|
||||
outerStack.leftAnchor equalTo view.leftAnchor
|
||||
|
@ -136,6 +141,26 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
}
|
||||
}
|
||||
|
||||
override fun viewWillAppear() {
|
||||
super.viewWillAppear()
|
||||
currentTabController.viewWillAppear()
|
||||
}
|
||||
|
||||
override fun viewDidAppear() {
|
||||
super.viewDidAppear()
|
||||
currentTabController.viewDidAppear()
|
||||
}
|
||||
|
||||
override fun viewWillDisappear() {
|
||||
super.viewWillDisappear()
|
||||
currentTabController.viewWillDisappear()
|
||||
}
|
||||
|
||||
override fun viewDidDisappear() {
|
||||
super.viewDidDisappear()
|
||||
currentTabController.viewDidDisappear()
|
||||
}
|
||||
|
||||
private fun updateTabButtons() {
|
||||
while (tabStack.arrangedSubviews.isNotEmpty()) tabStack.removeArrangedSubview(tabStack.arrangedSubviews.first())
|
||||
|
||||
|
@ -186,8 +211,20 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
tabButtons.forEach {
|
||||
it.setSelected(it.tab === tab)
|
||||
}
|
||||
oldTab.controller.removeFromParent()
|
||||
embedChild(currentTab.controller, tabVCContainer)
|
||||
currentTabController.viewWillDisappear()
|
||||
currentTabController.view.removeFromSuperview()
|
||||
currentTabController.viewDidDisappear()
|
||||
currentTabController.willMoveTo(null)
|
||||
currentTabController.removeFromParent()
|
||||
currentTabController.didMoveTo(null)
|
||||
|
||||
currentTabController = currentTab.controller
|
||||
|
||||
currentTabController.willMoveTo(this)
|
||||
embedChild(currentTabController, tabVCContainer)
|
||||
currentTabController.didMoveTo(this)
|
||||
currentTabController.viewWillAppear()
|
||||
currentTabController.viewDidAppear()
|
||||
|
||||
onTabChange?.invoke(currentTab)
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
|||
|
||||
override var providerPriority = 0
|
||||
override var receiverPriority = 0
|
||||
var syncPriorities = true
|
||||
|
||||
// todo: should this be a weak ref?
|
||||
private var inventory: GroupedItemInv? = null
|
||||
|
@ -121,11 +122,13 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
|||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||
tag.putInt("ProviderPriority", providerPriority)
|
||||
tag.putInt("ReceiverPriority", receiverPriority)
|
||||
tag.putBoolean("SyncPriorities", syncPriorities)
|
||||
}
|
||||
|
||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||
providerPriority = tag.getInt("ProviderPriority")
|
||||
receiverPriority = tag.getInt("ReceiverPriority")
|
||||
syncPriorities = tag.getBoolean("SyncPriorities")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,13 +2,20 @@ package net.shadowfacts.phycon.block.terminal
|
|||
|
||||
import alexiil.mc.lib.attributes.AttributeList
|
||||
import alexiil.mc.lib.attributes.AttributeProvider
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.sound.BlockSoundGroup
|
||||
import net.minecraft.state.StateManager
|
||||
import net.minecraft.state.property.Properties
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.ItemScatterer
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
|
@ -18,7 +25,7 @@ import net.minecraft.world.WorldAccess
|
|||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
import net.shadowfacts.phycon.block.DeviceBlock
|
||||
import java.util.*
|
||||
import java.util.EnumSet
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -33,10 +40,23 @@ class TerminalBlock: DeviceBlock<TerminalBlockEntity>(
|
|||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
|
||||
val FACING = Properties.FACING
|
||||
}
|
||||
|
||||
override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): Collection<Direction> {
|
||||
return EnumSet.allOf(Direction::class.java)
|
||||
val set = EnumSet.allOf(Direction::class.java)
|
||||
set.remove(state[FACING])
|
||||
return set
|
||||
}
|
||||
|
||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||
super.appendProperties(builder)
|
||||
builder.add(FACING)
|
||||
}
|
||||
|
||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||
val facing = if (context.player?.isSneaking == true) context.side else context.playerFacing.opposite
|
||||
return defaultState.with(FACING, facing)
|
||||
}
|
||||
|
||||
override fun createBlockEntity(world: BlockView) = TerminalBlockEntity()
|
||||
|
|
|
@ -3,11 +3,16 @@ package net.shadowfacts.phycon.screen.console
|
|||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.text.TranslatableText
|
||||
import net.shadowfacts.cacao.geometry.Axis
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.view.Label
|
||||
import net.shadowfacts.cacao.view.StackView
|
||||
import net.shadowfacts.cacao.view.View
|
||||
import net.shadowfacts.cacao.view.button.ToggleButton
|
||||
import net.shadowfacts.cacao.view.textfield.NumberField
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlockEntity
|
||||
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
|
||||
|
@ -18,6 +23,9 @@ class ProviderViewController<T>(
|
|||
private val device: T
|
||||
): ViewController() where T: BlockEntity, T: NetworkStackProvider {
|
||||
|
||||
private lateinit var field: NumberField
|
||||
private var syncButton: ToggleButton? = null
|
||||
|
||||
override fun viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
@ -26,9 +34,14 @@ class ProviderViewController<T>(
|
|||
}
|
||||
view.addSubview(label)
|
||||
|
||||
val field = NumberField(device.providerPriority) {
|
||||
field = NumberField(device.providerPriority) {
|
||||
if (it.number != null) {
|
||||
device.providerPriority = it.number!!
|
||||
|
||||
if (device is InterfaceBlockEntity && device.syncPriorities) {
|
||||
device.receiverPriority = it.number!!
|
||||
}
|
||||
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +52,30 @@ class ProviderViewController<T>(
|
|||
}
|
||||
view.addSubview(desc)
|
||||
|
||||
if (device is InterfaceBlockEntity) {
|
||||
val syncLabel = Label(TranslatableText("gui.phycon.console.provider.sync")).apply {
|
||||
textColor = Color.TEXT
|
||||
textAlignment = Label.TextAlignment.RIGHT
|
||||
}
|
||||
view.addSubview(syncLabel)
|
||||
|
||||
val syncButton = ToggleButton(device.syncPriorities) {
|
||||
device.syncPriorities = it.state
|
||||
device.receiverPriority = device.providerPriority
|
||||
}
|
||||
this.syncButton = syncButton
|
||||
view.addSubview(syncButton)
|
||||
|
||||
view.solver.dsl {
|
||||
syncButton.topAnchor equalTo (desc.bottomAnchor + 4)
|
||||
syncButton.leftAnchor equalTo field.leftAnchor
|
||||
|
||||
syncLabel.centerYAnchor equalTo syncButton.centerYAnchor
|
||||
syncLabel.leftAnchor equalTo view.leftAnchor
|
||||
syncLabel.rightAnchor equalTo (syncButton.leftAnchor - 4)
|
||||
}
|
||||
}
|
||||
|
||||
view.solver.dsl {
|
||||
field.widthAnchor equalTo 100
|
||||
field.heightAnchor equalTo 20
|
||||
|
@ -54,4 +91,13 @@ class ProviderViewController<T>(
|
|||
}
|
||||
}
|
||||
|
||||
override fun viewWillAppear() {
|
||||
super.viewWillAppear()
|
||||
|
||||
field.number = device.providerPriority
|
||||
if (device is InterfaceBlockEntity) {
|
||||
syncButton!!.state = device.syncPriorities
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@ import net.minecraft.client.MinecraftClient
|
|||
import net.minecraft.text.TranslatableText
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.view.Label
|
||||
import net.shadowfacts.cacao.view.button.ToggleButton
|
||||
import net.shadowfacts.cacao.view.textfield.NumberField
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlockEntity
|
||||
import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
|
||||
|
@ -18,6 +20,9 @@ class ReceiverViewController<T>(
|
|||
private val device: T
|
||||
): ViewController() where T: BlockEntity, T: NetworkStackReceiver {
|
||||
|
||||
private lateinit var field: NumberField
|
||||
private var syncButton: ToggleButton? = null
|
||||
|
||||
override fun viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
@ -26,9 +31,14 @@ class ReceiverViewController<T>(
|
|||
}
|
||||
view.addSubview(label)
|
||||
|
||||
val field = NumberField(device.receiverPriority) {
|
||||
field = NumberField(device.receiverPriority) {
|
||||
if (it.number != null) {
|
||||
device.receiverPriority = it.number!!
|
||||
|
||||
if (device is InterfaceBlockEntity && device.syncPriorities) {
|
||||
device.providerPriority = it.number!!
|
||||
}
|
||||
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +49,30 @@ class ReceiverViewController<T>(
|
|||
}
|
||||
view.addSubview(desc)
|
||||
|
||||
if (device is InterfaceBlockEntity) {
|
||||
val syncLabel = Label(TranslatableText("gui.phycon.console.receiver.sync")).apply {
|
||||
textColor = Color.TEXT
|
||||
textAlignment = Label.TextAlignment.RIGHT
|
||||
}
|
||||
view.addSubview(syncLabel)
|
||||
|
||||
val syncButton = ToggleButton(device.syncPriorities) {
|
||||
device.syncPriorities = it.state
|
||||
device.providerPriority = device.receiverPriority
|
||||
}
|
||||
this.syncButton = syncButton
|
||||
view.addSubview(syncButton)
|
||||
|
||||
view.solver.dsl {
|
||||
syncButton.topAnchor equalTo (desc.bottomAnchor + 4)
|
||||
syncButton.leftAnchor equalTo field.leftAnchor
|
||||
|
||||
syncLabel.centerYAnchor equalTo syncButton.centerYAnchor
|
||||
syncLabel.leftAnchor equalTo view.leftAnchor
|
||||
syncLabel.rightAnchor equalTo (syncButton.leftAnchor - 4)
|
||||
}
|
||||
}
|
||||
|
||||
view.solver.dsl {
|
||||
field.widthAnchor equalTo 100
|
||||
field.heightAnchor equalTo 20
|
||||
|
@ -54,4 +88,13 @@ class ReceiverViewController<T>(
|
|||
}
|
||||
}
|
||||
|
||||
override fun viewWillAppear() {
|
||||
super.viewWillAppear()
|
||||
|
||||
field.number = device.receiverPriority
|
||||
if (device is InterfaceBlockEntity) {
|
||||
syncButton!!.state = device.syncPriorities
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,9 +24,11 @@
|
|||
"gui.phycon.console.provider": "Item Provider",
|
||||
"gui.phycon.console.provider.priority": "Provider Priority",
|
||||
"gui.phycon.console.provider.priority_desc": "When a device requests items from the network, it send requests to providers (e.g., interfaces) with higher priorities first. Priorities can be negative.",
|
||||
"gui.phycon.console.provider.sync": "Sync with Receiver Priority",
|
||||
"gui.phycon.console.receiver": "Item Receiver",
|
||||
"gui.phycon.console.receiver.priority": "Receiver Priority",
|
||||
"gui.phycon.console.receiver.priority_desc": "When a device puts items into the network, it starts with receiver (e.g., interfaces) with higher priorities. Priorities can be negative.",
|
||||
"gui.phycon.console.receiver.sync": "Sync with Provider Priority",
|
||||
"gui.phycon.redstone_mode.high": "High",
|
||||
"gui.phycon.redstone_mode.low": "Low",
|
||||
"gui.phycon.redstone_mode.toggle": "Toggle",
|
||||
|
|
Loading…
Reference in New Issue