Color picker panel
This commit is contained in:
parent
9394de61d9
commit
4daa0be19a
@ -139,6 +139,8 @@ private fun misc(provider: MatteryLanguageProvider) {
|
|||||||
gui("exopack.go_back", "Open vanilla inventory")
|
gui("exopack.go_back", "Open vanilla inventory")
|
||||||
gui("exopack.go_in", "Open Exopack inventory")
|
gui("exopack.go_in", "Open Exopack inventory")
|
||||||
gui("exopack.toggle_visibility", "Toggle Exopack visibility")
|
gui("exopack.toggle_visibility", "Toggle Exopack visibility")
|
||||||
|
gui("exopack.change_color", "Customize Exopack color")
|
||||||
|
gui("exopack.change_color2", "Press Middle Mouse Button to remove color")
|
||||||
|
|
||||||
gui("exopack.probe1", "This little device feels unnatural to touch, it is almost certainly resilient to any possible attempt to break it open.")
|
gui("exopack.probe1", "This little device feels unnatural to touch, it is almost certainly resilient to any possible attempt to break it open.")
|
||||||
gui("exopack.probe2", "There is fingerprint reader built into one of sides which gently glow when touched.")
|
gui("exopack.probe2", "There is fingerprint reader built into one of sides which gently glow when touched.")
|
||||||
@ -664,6 +666,22 @@ private fun gui(provider: MatteryLanguageProvider) {
|
|||||||
with(provider.english) {
|
with(provider.english) {
|
||||||
gui("quicksearch", "Quick search...")
|
gui("quicksearch", "Quick search...")
|
||||||
|
|
||||||
|
gui("color_picker", "Color Picker")
|
||||||
|
|
||||||
|
gui("color.short.red", "R")
|
||||||
|
gui("color.short.green", "G")
|
||||||
|
gui("color.short.blue", "B")
|
||||||
|
gui("color.short.hue", "H")
|
||||||
|
gui("color.short.saturation", "S")
|
||||||
|
gui("color.short.value", "V")
|
||||||
|
|
||||||
|
gui("color.full.red", "Red")
|
||||||
|
gui("color.full.green", "Green")
|
||||||
|
gui("color.full.blue", "Blue")
|
||||||
|
gui("color.full.hue", "Hue")
|
||||||
|
gui("color.full.saturation", "Saturation")
|
||||||
|
gui("color.full.value", "Value")
|
||||||
|
|
||||||
gui("item_monitor.refill_source.desc", "Controls from where to take items for slot auto refill")
|
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.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")
|
gui("item_monitor.refill_source.inventory", "Inventory only. Crafting grid will be auto refilled only from player's inventory")
|
||||||
|
@ -147,6 +147,8 @@ private fun misc(provider: MatteryLanguageProvider) {
|
|||||||
gui("exopack.go_back", "Открыть обычный инвентарь")
|
gui("exopack.go_back", "Открыть обычный инвентарь")
|
||||||
gui("exopack.go_in", "Открыть инвентарь экзопака")
|
gui("exopack.go_in", "Открыть инвентарь экзопака")
|
||||||
gui("exopack.toggle_visibility", "Переключить отображение Экзопака")
|
gui("exopack.toggle_visibility", "Переключить отображение Экзопака")
|
||||||
|
gui("exopack.change_color", "Изменить окраску Экзопака")
|
||||||
|
gui("exopack.change_color2", "Нажмите среднюю кнопку мыши для сброса окраски")
|
||||||
|
|
||||||
gui("exopack.probe1", "Данное маленькое устройство необычно на ощупь, а так же неприступно для любых попыток вскрыть.")
|
gui("exopack.probe1", "Данное маленькое устройство необычно на ощупь, а так же неприступно для любых попыток вскрыть.")
|
||||||
gui("exopack.probe2", "На одной из сторон данного устройства находится сканер отпечатка, который тускло загорается при касании.")
|
gui("exopack.probe2", "На одной из сторон данного устройства находится сканер отпечатка, который тускло загорается при касании.")
|
||||||
@ -668,6 +670,22 @@ private fun gui(provider: MatteryLanguageProvider) {
|
|||||||
with(provider.russian) {
|
with(provider.russian) {
|
||||||
gui("quicksearch", "Быстрый поиск...")
|
gui("quicksearch", "Быстрый поиск...")
|
||||||
|
|
||||||
|
gui("color_picker", "Выбор цвета")
|
||||||
|
|
||||||
|
gui("color.short.red", "К")
|
||||||
|
gui("color.short.green", "З")
|
||||||
|
gui("color.short.blue", "С")
|
||||||
|
gui("color.short.hue", "Ц")
|
||||||
|
gui("color.short.saturation", "Н")
|
||||||
|
gui("color.short.value", "Я")
|
||||||
|
|
||||||
|
gui("color.full.red", "Красный")
|
||||||
|
gui("color.full.green", "Зелёный")
|
||||||
|
gui("color.full.blue", "Синий")
|
||||||
|
gui("color.full.hue", "Цвет")
|
||||||
|
gui("color.full.saturation", "Насыщение")
|
||||||
|
gui("color.full.value", "Яркость")
|
||||||
|
|
||||||
gui("item_monitor.refill_source.desc", "Контролирует источник предметов для заполнения сетки создания")
|
gui("item_monitor.refill_source.desc", "Контролирует источник предметов для заполнения сетки создания")
|
||||||
gui("item_monitor.refill_source.system", "Только система. Сетка создания будет заполняться только из системы предметов. Данный параметр соответствует поведению AE2 и Refined Storage")
|
gui("item_monitor.refill_source.system", "Только система. Сетка создания будет заполняться только из системы предметов. Данный параметр соответствует поведению AE2 и Refined Storage")
|
||||||
gui("item_monitor.refill_source.inventory", "Только инвентарь. Сетка создания будет заполняться только из инвентаря игрока")
|
gui("item_monitor.refill_source.inventory", "Только инвентарь. Сетка создания будет заполняться только из инвентаря игрока")
|
||||||
|
@ -0,0 +1,746 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.client.screen.panels
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.InputConstants
|
||||||
|
import com.mojang.datafixers.util.Either
|
||||||
|
import it.unimi.dsi.fastutil.floats.FloatConsumer
|
||||||
|
import net.minecraft.client.gui.GuiGraphics
|
||||||
|
import net.minecraft.client.gui.screens.Screen
|
||||||
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.resources.ResourceLocation
|
||||||
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
|
import ru.dbotthepony.mc.otm.client.playGuiClickSound
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.MatterySprite
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.RenderGravity
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.WidgetLocation
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.renderRect
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.AbstractButtonPanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel
|
||||||
|
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||||
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
|
import ru.dbotthepony.mc.otm.core.math.HSVColor
|
||||||
|
import ru.dbotthepony.mc.otm.core.math.RGBAColor
|
||||||
|
import java.util.function.Consumer
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
open class ColorBoxPanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
x: Float,
|
||||||
|
y: Float,
|
||||||
|
width: Float = 64f,
|
||||||
|
height: Float = 64f,
|
||||||
|
protected val callback: Consumer<HSVColor>? = null,
|
||||||
|
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
||||||
|
var backgroundColor = RGBAColor.RED
|
||||||
|
private set
|
||||||
|
var markerPos = backgroundColor.toHSV()
|
||||||
|
protected set
|
||||||
|
|
||||||
|
fun setColor(color: Either<RGBAColor, HSVColor>) {
|
||||||
|
color.map(
|
||||||
|
{ markerPos = it.toHSV(); if (it.canRepresentHue()) backgroundColor = HSVColor(it.toHSV().hue, 1f, 1f).toRGBA() },
|
||||||
|
{ markerPos = it; backgroundColor = HSVColor(it.hue, 1f, 1f).toRGBA() })
|
||||||
|
}
|
||||||
|
|
||||||
|
var isPressed = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
override fun shouldRenderTooltips(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
|
||||||
|
return super.shouldRenderTooltips(graphics, mouseX, mouseY, partialTick) || isPressed
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun onPickedColor(color: HSVColor) {
|
||||||
|
callback?.accept(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun pickColor(mouseX: Double, mouseY: Double) {
|
||||||
|
val (x, y) = screenToLocal(mouseX, mouseY)
|
||||||
|
|
||||||
|
val saturation = 1f - x.coerceIn(0f, width) / width
|
||||||
|
val value = 1f - y.coerceIn(0f, height) / height
|
||||||
|
|
||||||
|
markerPos = HSVColor(backgroundColor.toHSV().hue, saturation, value)
|
||||||
|
onPickedColor(markerPos)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
||||||
|
if (button == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||||
|
if (!isPressed) {
|
||||||
|
isPressed = true
|
||||||
|
grabMouseInput = true
|
||||||
|
|
||||||
|
pickColor(x, y)
|
||||||
|
playGuiClickSound()
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseClickedInner(x, y, button)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseDraggedInner(x: Double, y: Double, button: Int, xDelta: Double, yDelta: Double): Boolean {
|
||||||
|
if (isPressed && button == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||||
|
pickColor(x, y)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseDraggedInner(x, y, button, xDelta, yDelta)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseReleasedInner(x: Double, y: Double, button: Int): Boolean {
|
||||||
|
if (button == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||||
|
if (isPressed) {
|
||||||
|
isPressed = false
|
||||||
|
grabMouseInput = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseReleasedInner(x, y, button)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
|
graphics.renderRect(0f, 0f, width, height, color = RGBAColor.WHITE)
|
||||||
|
GRADIENT_LEFT.render(graphics, 0f, 0f, width, height, color = backgroundColor)
|
||||||
|
GRADIENT_DOWN.render(graphics, 0f, 0f, width, height, color = RGBAColor.BLACK)
|
||||||
|
|
||||||
|
val x = (1f - markerPos.saturation) * width
|
||||||
|
val y = (1f - markerPos.value) * height
|
||||||
|
|
||||||
|
LINE_VERTICAL.render(graphics, x = x - 1f, height = height)
|
||||||
|
LINE_HORIZONTAL.render(graphics, y = y - 1f, width = width)
|
||||||
|
LINE_CROSS.render(graphics, x = x - 1f, y = y - 1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val GRADIENT_UP = MatterySprite(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/gradient_v.png"), 0f, 0f, 32f, 256f, 32f, 256f)
|
||||||
|
val GRADIENT_DOWN = GRADIENT_UP.copy(winding = UVWindingOrder.FLIP)
|
||||||
|
val GRADIENT_RIGHT = MatterySprite(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/gradient_h.png"), 0f, 0f, 256f, 32f, 256f, 32f)
|
||||||
|
val GRADIENT_LEFT = GRADIENT_RIGHT.copy(winding = UVWindingOrder.FLOP)
|
||||||
|
|
||||||
|
val LINE_VERTICAL = WidgetLocation.MISC.sprite(36f, 0f, 3f, 3f)
|
||||||
|
val LINE_HORIZONTAL = WidgetLocation.MISC.sprite(36f, 3f, 3f, 3f)
|
||||||
|
val LINE_CROSS = WidgetLocation.MISC.sprite(36f, 6f, 3f, 3f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AbstractColorWangPanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = 40f,
|
||||||
|
height: Float = 10f,
|
||||||
|
protected val callback: Consumer<RGBAColor>? = null,
|
||||||
|
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
||||||
|
abstract val leftColor: RGBAColor
|
||||||
|
abstract val rightColor: RGBAColor
|
||||||
|
abstract val wangPosition: Float
|
||||||
|
abstract fun setColor(color: Either<RGBAColor, HSVColor>)
|
||||||
|
protected abstract fun onWangInput(newPosition: Float)
|
||||||
|
|
||||||
|
init {
|
||||||
|
scissor = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var isPressed = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
protected fun updateColor(mouseX: Double) {
|
||||||
|
onWangInput((screenToLocal(mouseX, 0.0).x / width).coerceIn(0f, 1f))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
||||||
|
if (button == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||||
|
if (!isPressed) {
|
||||||
|
isPressed = true
|
||||||
|
grabMouseInput = true
|
||||||
|
|
||||||
|
updateColor(x)
|
||||||
|
playGuiClickSound()
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseClickedInner(x, y, button)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseDraggedInner(x: Double, y: Double, button: Int, xDelta: Double, yDelta: Double): Boolean {
|
||||||
|
if (isPressed && button == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||||
|
updateColor(x)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseDraggedInner(x, y, button, xDelta, yDelta)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseReleasedInner(x: Double, y: Double, button: Int): Boolean {
|
||||||
|
if (button == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||||
|
if (isPressed) {
|
||||||
|
isPressed = false
|
||||||
|
grabMouseInput = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseReleasedInner(x, y, button)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun renderGradients(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
|
ColorBoxPanel.GRADIENT_RIGHT.render(graphics, 0f, 0f, width, height, color = rightColor)
|
||||||
|
ColorBoxPanel.GRADIENT_LEFT.render(graphics, 0f, 0f, width, height, color = leftColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun renderWang(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
|
if (wangPosition in 0f .. 1f) {
|
||||||
|
ColorBoxPanel.LINE_VERTICAL.render(graphics, x = wangPosition * width - 1f, height = height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
|
renderGradients(graphics, mouseX, mouseY, partialTick)
|
||||||
|
renderWang(graphics, mouseX, mouseY, partialTick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class RedColorWangPanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = 40f,
|
||||||
|
height: Float = 10f,
|
||||||
|
callback: Consumer<RGBAColor>? = null,
|
||||||
|
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height, callback) {
|
||||||
|
override var leftColor: RGBAColor = RGBAColor.BLACK
|
||||||
|
protected set
|
||||||
|
override var rightColor: RGBAColor = RGBAColor.RED
|
||||||
|
protected set
|
||||||
|
override var wangPosition: Float = 0f
|
||||||
|
protected set
|
||||||
|
|
||||||
|
override fun onWangInput(newPosition: Float) {
|
||||||
|
val color = leftColor.copy(red = newPosition)
|
||||||
|
wangPosition = newPosition
|
||||||
|
callback?.accept(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setColor(color: Either<RGBAColor, HSVColor>) {
|
||||||
|
@Suppress("name_shadowing")
|
||||||
|
val color = color.map({ it }, { it.toRGBA() })
|
||||||
|
leftColor = color.copy(red = 0f, alpha = 1f)
|
||||||
|
rightColor = color.copy(red = 1f, alpha = 1f)
|
||||||
|
wangPosition = color.red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class GreenColorWangPanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = 40f,
|
||||||
|
height: Float = 10f,
|
||||||
|
callback: Consumer<RGBAColor>? = null,
|
||||||
|
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height, callback) {
|
||||||
|
override var leftColor: RGBAColor = RGBAColor.BLACK
|
||||||
|
protected set
|
||||||
|
override var rightColor: RGBAColor = RGBAColor.GREEN
|
||||||
|
protected set
|
||||||
|
override var wangPosition: Float = 0f
|
||||||
|
protected set
|
||||||
|
|
||||||
|
override fun onWangInput(newPosition: Float) {
|
||||||
|
val color = leftColor.copy(green = newPosition)
|
||||||
|
wangPosition = newPosition
|
||||||
|
callback?.accept(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setColor(color: Either<RGBAColor, HSVColor>) {
|
||||||
|
@Suppress("name_shadowing")
|
||||||
|
val color = color.map({ it }, { it.toRGBA() })
|
||||||
|
leftColor = color.copy(green = 0f, alpha = 1f)
|
||||||
|
rightColor = color.copy(green = 1f, alpha = 1f)
|
||||||
|
wangPosition = color.green
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BlueColorWangPanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = 40f,
|
||||||
|
height: Float = 10f,
|
||||||
|
callback: Consumer<RGBAColor>? = null,
|
||||||
|
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height, callback) {
|
||||||
|
override var leftColor: RGBAColor = RGBAColor.BLACK
|
||||||
|
protected set
|
||||||
|
override var rightColor: RGBAColor = RGBAColor.BLUE
|
||||||
|
protected set
|
||||||
|
override var wangPosition: Float = 0f
|
||||||
|
protected set
|
||||||
|
|
||||||
|
override fun onWangInput(newPosition: Float) {
|
||||||
|
val color = leftColor.copy(blue = newPosition)
|
||||||
|
wangPosition = newPosition
|
||||||
|
callback?.accept(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setColor(color: Either<RGBAColor, HSVColor>) {
|
||||||
|
@Suppress("name_shadowing")
|
||||||
|
val color = color.map({ it }, { it.toRGBA() })
|
||||||
|
leftColor = color.copy(blue = 0f, alpha = 1f)
|
||||||
|
rightColor = color.copy(blue = 1f, alpha = 1f)
|
||||||
|
wangPosition = color.blue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class HueWangPanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = 40f,
|
||||||
|
height: Float = 10f,
|
||||||
|
protected val hueCallback: FloatConsumer? = null,
|
||||||
|
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height) {
|
||||||
|
override val leftColor: RGBAColor get() = RGBAColor.WHITE
|
||||||
|
override val rightColor: RGBAColor get() = RGBAColor.WHITE
|
||||||
|
override var wangPosition: Float = 1f
|
||||||
|
protected set
|
||||||
|
|
||||||
|
override fun setColor(color: Either<RGBAColor, HSVColor>) {
|
||||||
|
color.map(
|
||||||
|
{
|
||||||
|
if (it.canRepresentHue()) {
|
||||||
|
wangPosition = it.toHSV().hue / 360f
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
wangPosition = it.hue / 360f
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onWangInput(newPosition: Float) {
|
||||||
|
wangPosition = newPosition
|
||||||
|
hueCallback?.accept(newPosition * 360f)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
|
HSV_BAR.render(graphics, 0f, 0f, width, height)
|
||||||
|
renderWang(graphics, mouseX, mouseY, partialTick)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val HSV_BAR = MatterySprite(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/hsv.png"), 0f, 0f, 256f, 16f, 256f, 16f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class SaturationWangPanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = 40f,
|
||||||
|
height: Float = 10f,
|
||||||
|
protected val saturationCallback: FloatConsumer? = null,
|
||||||
|
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height) {
|
||||||
|
override var leftColor: RGBAColor = RGBAColor.WHITE
|
||||||
|
protected set
|
||||||
|
override var rightColor: RGBAColor = RGBAColor.WHITE
|
||||||
|
protected set
|
||||||
|
override var wangPosition: Float = 1f
|
||||||
|
protected set
|
||||||
|
|
||||||
|
override fun onWangInput(newPosition: Float) {
|
||||||
|
wangPosition = newPosition
|
||||||
|
saturationCallback?.accept(newPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setColor(color: Either<RGBAColor, HSVColor>) {
|
||||||
|
color.map(
|
||||||
|
{
|
||||||
|
val hsv = it.toHSV()
|
||||||
|
|
||||||
|
if (it.canRepresentHue()) {
|
||||||
|
leftColor = hsv.copy(saturation = 0f).toRGBA()
|
||||||
|
rightColor = hsv.copy(saturation = 1f).toRGBA()
|
||||||
|
} else {
|
||||||
|
leftColor = hsv.copy(hue = leftColor.toHSV().hue, saturation = 0f).toRGBA()
|
||||||
|
rightColor = hsv.copy(hue = rightColor.toHSV().hue, saturation = 1f).toRGBA()
|
||||||
|
}
|
||||||
|
|
||||||
|
wangPosition = hsv.saturation
|
||||||
|
},
|
||||||
|
{ hsv ->
|
||||||
|
leftColor = hsv.copy(saturation = 0f).toRGBA()
|
||||||
|
rightColor = hsv.copy(saturation = 1f).toRGBA()
|
||||||
|
wangPosition = hsv.saturation
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class ValueWangPanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = 40f,
|
||||||
|
height: Float = 10f,
|
||||||
|
protected val valueCallback: FloatConsumer? = null,
|
||||||
|
) : AbstractColorWangPanel<S>(screen, parent, x, y, width, height) {
|
||||||
|
override var leftColor: RGBAColor = RGBAColor.BLACK
|
||||||
|
protected set
|
||||||
|
override var rightColor: RGBAColor = RGBAColor.WHITE
|
||||||
|
protected set
|
||||||
|
override var wangPosition: Float = 1f
|
||||||
|
protected set
|
||||||
|
|
||||||
|
override fun onWangInput(newPosition: Float) {
|
||||||
|
wangPosition = newPosition
|
||||||
|
valueCallback?.accept(newPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setColor(color: Either<RGBAColor, HSVColor>) {
|
||||||
|
color.map(
|
||||||
|
{
|
||||||
|
val hsv = it.toHSV()
|
||||||
|
|
||||||
|
if (it.canRepresentHue()) {
|
||||||
|
leftColor = hsv.copy(value = 0f).toRGBA()
|
||||||
|
rightColor = hsv.copy(value = 1f).toRGBA()
|
||||||
|
} else {
|
||||||
|
leftColor = hsv.copy(hue = leftColor.toHSV().hue, value = 0f).toRGBA()
|
||||||
|
rightColor = hsv.copy(hue = rightColor.toHSV().hue, value = 1f).toRGBA()
|
||||||
|
}
|
||||||
|
|
||||||
|
wangPosition = hsv.value
|
||||||
|
},
|
||||||
|
{ hsv ->
|
||||||
|
leftColor = hsv.copy(value = 0f).toRGBA()
|
||||||
|
rightColor = hsv.copy(value = 1f).toRGBA()
|
||||||
|
wangPosition = hsv.value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class ColorPalettePanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = 64f,
|
||||||
|
height: Float = 64f,
|
||||||
|
protected val callback: Consumer<RGBAColor>? = null
|
||||||
|
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
||||||
|
open fun onColorChoose(color: RGBAColor) {
|
||||||
|
callback?.accept(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Button(val color: RGBAColor) : AbstractButtonPanel<S>(screen, this@ColorPalettePanel, 0f, 0f, 8f, 8f) {
|
||||||
|
init {
|
||||||
|
tooltips.add(TextComponent("${color.redInt}, ${color.greenInt}, ${color.blueInt}"))
|
||||||
|
tooltips.add(TextComponent(color.toHexStringRGB()))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(mouseButton: Int) {
|
||||||
|
onColorChoose(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
|
graphics.renderRect(0f, 0f, width, height, color = RGBAColor.BLACK)
|
||||||
|
graphics.renderRect(1f, 1f, width - 2f, height - 2f, color = color)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun compareTo(other: EditablePanel<*>): Int {
|
||||||
|
return super.compareTo(other).let {
|
||||||
|
if (it != 0 || other !is Button)
|
||||||
|
it
|
||||||
|
else
|
||||||
|
color.compareTo(other.color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun performLayout() {
|
||||||
|
super.performLayout()
|
||||||
|
|
||||||
|
var x = 0f
|
||||||
|
var y = 0f
|
||||||
|
|
||||||
|
for (children in visibleChildren) {
|
||||||
|
if (children is Button) {
|
||||||
|
if (x != 0f && x + children.width > width) {
|
||||||
|
y += 9f
|
||||||
|
x = 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
children.x = x
|
||||||
|
children.y = y
|
||||||
|
x += 9f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class ColorPickerPanel<out S : Screen>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = 164f,
|
||||||
|
height: Float = 118f,
|
||||||
|
val callback: Consumer<RGBAColor>? = null
|
||||||
|
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
||||||
|
open fun onColorChanged(color: RGBAColor) {
|
||||||
|
callback?.accept(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentColor: Either<RGBAColor, HSVColor> = Either.left(RGBAColor.WHITE)
|
||||||
|
protected set
|
||||||
|
|
||||||
|
fun setColor(color: Either<RGBAColor, HSVColor>) {
|
||||||
|
currentColor = color
|
||||||
|
hexInput.text = color.map({ it }, { it.toRGBA() }).toHexStringRGB()
|
||||||
|
updateWangs(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun updateWangs(color: Either<RGBAColor, HSVColor>) {
|
||||||
|
box.setColor(color)
|
||||||
|
|
||||||
|
for (wang in wangs)
|
||||||
|
wang.update(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun onPaletteChoose(color: RGBAColor) {
|
||||||
|
setColor(Either.left(color))
|
||||||
|
onColorChanged(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun onColorBoxChoose(color: HSVColor) {
|
||||||
|
setColor(Either.right(color))
|
||||||
|
onColorChanged(color.toRGBA())
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun onWangChoose(color: RGBAColor) {
|
||||||
|
setColor(Either.left(color))
|
||||||
|
onColorChanged(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun onHueChoose(hue: Float) {
|
||||||
|
val current = currentColor.map({ it.toHSV() }, { it })
|
||||||
|
val new = current.copy(hue = hue)
|
||||||
|
setColor(Either.right(new))
|
||||||
|
onColorChanged(new.toRGBA())
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun onSaturationChoose(saturation: Float) {
|
||||||
|
val current = currentColor.map({ it.toHSV() }, { it })
|
||||||
|
val new = current.copy(saturation = saturation)
|
||||||
|
setColor(Either.right(new))
|
||||||
|
onColorChanged(new.toRGBA())
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun onValueChoose(value: Float) {
|
||||||
|
val current = currentColor.map({ it.toHSV() }, { it })
|
||||||
|
val new = current.copy(value = value)
|
||||||
|
setColor(Either.right(new))
|
||||||
|
onColorChanged(new.toRGBA())
|
||||||
|
}
|
||||||
|
|
||||||
|
val topStrip = EditablePanel(screen, this, 0f, 0f, width = width, height = 70f)
|
||||||
|
val middleStrip = EditablePanel(screen, this)
|
||||||
|
val palette = ColorPalettePanel(screen, this, callback = { onPaletteChoose(it) })
|
||||||
|
|
||||||
|
val hexInput = object : TextInputPanel<S>(screen, middleStrip, width = 50f) {
|
||||||
|
init {
|
||||||
|
dock = Dock.RIGHT
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFocusChanged() {
|
||||||
|
if (!isFocusedThis) {
|
||||||
|
val newColor = RGBAColor.fromHexStringRGB(text)
|
||||||
|
|
||||||
|
if (newColor == null) {
|
||||||
|
text = currentColor.map({ it }, { it.toRGBA() }).toHexStringRGB()
|
||||||
|
} else {
|
||||||
|
setColor(Either.left(newColor))
|
||||||
|
onColorChanged(newColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun acceptsCharacter(codepoint: Char, mods: Int): Boolean {
|
||||||
|
return RGBAColor.isHexCharacter(codepoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
topStrip.dock = Dock.TOP
|
||||||
|
middleStrip.dock = Dock.TOP
|
||||||
|
palette.dock = Dock.FILL
|
||||||
|
palette.dockTop = 2f
|
||||||
|
middleStrip.dockTop = 2f
|
||||||
|
|
||||||
|
for (color in paletteColors) {
|
||||||
|
palette.Button(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val box = ColorBoxPanel(screen, topStrip, 0f, 0f, width = 70f, height = 70f, callback = { onColorBoxChoose(it) })
|
||||||
|
val wangCanvas = EditablePanel(screen, topStrip, width = 80f)
|
||||||
|
|
||||||
|
inner class WangLine(label: String, val wang: AbstractColorWangPanel<S>, val text: (color: Either<RGBAColor, HSVColor>) -> Component?) {
|
||||||
|
val canvas = EditablePanel(screen, wangCanvas, height = 10f)
|
||||||
|
val label = Label(screen, canvas, width = 10f, text = TranslatableComponent("otm.gui.color.short.$label"))
|
||||||
|
val textLabel = Label(screen, canvas, width = 25f)
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.wang.parent = canvas
|
||||||
|
this.wang.width = 45f
|
||||||
|
|
||||||
|
this.label.childrenOrder = 0
|
||||||
|
this.wang.childrenOrder = 1
|
||||||
|
this.textLabel.childrenOrder = 2
|
||||||
|
|
||||||
|
this.canvas.dock = Dock.TOP
|
||||||
|
this.canvas.dockTop = 2f
|
||||||
|
|
||||||
|
this.label.dock = Dock.LEFT
|
||||||
|
this.label.dockRight = 2f
|
||||||
|
|
||||||
|
this.wang.dock = Dock.LEFT
|
||||||
|
this.wang.dockRight = 2f
|
||||||
|
|
||||||
|
this.textLabel.dock = Dock.LEFT
|
||||||
|
this.textLabel.align = RenderGravity.CENTER_LEFT
|
||||||
|
|
||||||
|
this.label.tooltips.add(TranslatableComponent("otm.gui.color.full.$label"))
|
||||||
|
this.label.align = RenderGravity.CENTER_RIGHT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(color: Either<RGBAColor, HSVColor>) {
|
||||||
|
wang.setColor(color)
|
||||||
|
|
||||||
|
text.invoke(color)?.let {
|
||||||
|
textLabel.text = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val red = WangLine("red", RedColorWangPanel(screen, wangCanvas, callback = { onWangChoose(it) })) { TextComponent((it.map({ it }, { it.toRGBA() }).red * 255f).roundToInt().toString()) }
|
||||||
|
val green = WangLine("green", GreenColorWangPanel(screen, wangCanvas, callback = { onWangChoose(it) })) { TextComponent((it.map({ it }, { it.toRGBA() }).green * 255f).roundToInt().toString()) }
|
||||||
|
val blue = WangLine("blue", BlueColorWangPanel(screen, wangCanvas, callback = { onWangChoose(it) })) { TextComponent((it.map({ it }, { it.toRGBA() }).blue * 255f).roundToInt().toString()) }
|
||||||
|
|
||||||
|
val hue = WangLine("hue", HueWangPanel(screen, wangCanvas, hueCallback = { onHueChoose(it) })) { it.map({ if (it.canRepresentHue()) it.toHSV() else null }, { it })?.let { TextComponent(it.hue.roundToInt().toString()) } }
|
||||||
|
val saturation = WangLine("saturation", SaturationWangPanel(screen, wangCanvas, saturationCallback = { onSaturationChoose(it) })) { it.map({ if (it.canRepresentHue()) it.toHSV() else null }, { it })?.let { TextComponent((it.saturation * 100f).roundToInt().toString() + "%") } }
|
||||||
|
val value = WangLine("value", ValueWangPanel(screen, wangCanvas, valueCallback = { onValueChoose(it) })) { it.map({ if (it.canRepresentHue()) it.toHSV() else null }, { it })?.let { TextComponent((it.value * 100f).roundToInt().toString() + "%") } }
|
||||||
|
|
||||||
|
val wangs = listOf(red, green, blue, hue, saturation, value)
|
||||||
|
|
||||||
|
init {
|
||||||
|
box.dock = Dock.LEFT
|
||||||
|
wangCanvas.dock = Dock.RIGHT
|
||||||
|
red.canvas.dockTop = 0f
|
||||||
|
|
||||||
|
setColor(Either.right(HSVColor.WHITE))
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val paletteColors = listOf(
|
||||||
|
RGBAColor.rgb(0x9b59b6L), // Amethyst
|
||||||
|
RGBAColor.rgb(0x010101L), // Black
|
||||||
|
RGBAColor.rgb(0x0000ffL), // Blue
|
||||||
|
RGBAColor.rgb(0x8B4513L), // Brown
|
||||||
|
RGBAColor.rgb(0xe67e22L), // Carrot
|
||||||
|
RGBAColor.rgb(0xD2691EL), // Chocolate
|
||||||
|
RGBAColor.rgb(0xecf0f1L), // Clouds
|
||||||
|
RGBAColor.rgb(0xFF7F50L), // Coral
|
||||||
|
RGBAColor.rgb(0xDC143CL), // Crimson
|
||||||
|
RGBAColor.rgb(0x00FFFFL), // Cyan
|
||||||
|
RGBAColor.rgb(0x008B8BL), // DarkCyan
|
||||||
|
RGBAColor.rgb(0xBDB76BL), // DarkGold
|
||||||
|
RGBAColor.rgb(0xB8860BL), // DarkGoldenRod
|
||||||
|
RGBAColor.rgb(0x006400L), // DarkGreen
|
||||||
|
RGBAColor.rgb(0x16a085L), // DarkGreen
|
||||||
|
RGBAColor.rgb(0x8B008BL), // DarkMagenta
|
||||||
|
RGBAColor.rgb(0x556B2FL), // DarkOlive
|
||||||
|
RGBAColor.rgb(0xFF8C00L), // DarkOrange
|
||||||
|
RGBAColor.rgb(0x8B0000L), // DarkRed
|
||||||
|
RGBAColor.rgb(0xE9967AL), // DarkSalmon
|
||||||
|
RGBAColor.rgb(0x9400D3L), // DarkViolet
|
||||||
|
RGBAColor.rgb(0xFF1493L), // DeepPink
|
||||||
|
RGBAColor.rgb(0x00BFFFL), // DeepSkyBlue
|
||||||
|
RGBAColor.rgb(0x2ecc71L), // Emerald
|
||||||
|
RGBAColor.rgb(0xB22222L), // FireBrick
|
||||||
|
RGBAColor.rgb(0x228B22L), // ForestGreen
|
||||||
|
RGBAColor.rgb(0xFF00FFL), // Fuchsia
|
||||||
|
RGBAColor.rgb(0xDCDCDCL), // Gainsboro
|
||||||
|
RGBAColor.rgb(0xFFD700L), // Gold
|
||||||
|
RGBAColor.rgb(0xDAA520L), // GoldenRod
|
||||||
|
RGBAColor.rgb(0x00B000L), // Green
|
||||||
|
RGBAColor.rgb(0x808080L), // Grey
|
||||||
|
RGBAColor.rgb(0xFF69B4L), // HotPink
|
||||||
|
RGBAColor.rgb(0x4B0082L), // Indigo
|
||||||
|
RGBAColor.rgb(0xF0E68CL), // Khaki
|
||||||
|
RGBAColor.rgb(0xE6E6FAL), // Lavender
|
||||||
|
RGBAColor.rgb(0xFF9FF7L), // LavenderRose
|
||||||
|
RGBAColor.rgb(0xD3D3D3L), // LightGrey
|
||||||
|
RGBAColor.rgb(0x87CEFAL), // LightSkyBlue
|
||||||
|
RGBAColor.rgb(0xFFFFE0L), // LightYellow
|
||||||
|
RGBAColor.rgb(0x00ff00L), // Lime
|
||||||
|
RGBAColor.rgb(0x32CD32L), // LimeGreen
|
||||||
|
RGBAColor.rgb(0xBA55D3L), // MediumOrchid
|
||||||
|
RGBAColor.rgb(0x9370DBL), // MediumPurple
|
||||||
|
RGBAColor.rgb(0x7B68EEL), // MediumSlateBlue
|
||||||
|
RGBAColor.rgb(0x808000L), // Olive
|
||||||
|
RGBAColor.rgb(0x6B8E23L), // OliveGreen
|
||||||
|
RGBAColor.rgb(0xFFA500L), // Orange
|
||||||
|
RGBAColor.rgb(0xDA70D6L), // Orchid
|
||||||
|
RGBAColor.rgb(0xDB7093L), // PaleVioletRed
|
||||||
|
RGBAColor.rgb(0xCD853FL), // Peru
|
||||||
|
RGBAColor.rgb(0xFFC0CBL), // Pink
|
||||||
|
RGBAColor.rgb(0xB0E0E6L), // PowderBlue
|
||||||
|
RGBAColor.rgb(0xd35400L), // Pumpkin
|
||||||
|
RGBAColor.rgb(0x800080L), // Purple
|
||||||
|
RGBAColor.rgb(0xff0000L), // Red
|
||||||
|
RGBAColor.rgb(0x4169E1L), // RoyalBlue
|
||||||
|
RGBAColor.rgb(0xFA8072L), // Salmon
|
||||||
|
RGBAColor.rgb(0xF4A460L), // SandyBrown
|
||||||
|
RGBAColor.rgb(0x2E8B57L), // SeaGreen
|
||||||
|
RGBAColor.rgb(0xA0522DL), // Sienna
|
||||||
|
RGBAColor.rgb(0xbdc3c7L), // Silver
|
||||||
|
RGBAColor.rgb(0x87CEEBL), // SkyBlue
|
||||||
|
RGBAColor.rgb(0x708090L), // SlateGrey
|
||||||
|
RGBAColor.rgb(0x4682B4L), // SteelBlue
|
||||||
|
RGBAColor.rgb(0xf1c40fL), // SunFlower
|
||||||
|
RGBAColor.rgb(0x008080L), // Teal
|
||||||
|
RGBAColor.rgb(0xD8BFD8L), // Thistle
|
||||||
|
RGBAColor.rgb(0xEE82EEL), // Violet
|
||||||
|
)
|
||||||
|
|
||||||
|
fun <S : MatteryScreen<*>> frame(screen: S, callback: Consumer<RGBAColor>, color: RGBAColor = RGBAColor.RED, title: Component? = TranslatableComponent("otm.gui.color_picker")): FramePanel<S> {
|
||||||
|
return FramePanel.padded(screen, 164f, 118f, title).also {
|
||||||
|
ColorPickerPanel(screen, it, 0f, 0f, callback = callback).also {
|
||||||
|
it.dock = Dock.FILL
|
||||||
|
it.setColor(Either.left(color))
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.addPanel(it)
|
||||||
|
it.toScreenCenter()
|
||||||
|
it.behaveAsWindow()
|
||||||
|
it.popup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 627 B |
Binary file not shown.
After Width: | Height: | Size: 682 B |
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
Loading…
Reference in New Issue
Block a user