Compare commits
7 Commits
e28daf3b4a
...
e9df08aa30
Author | SHA1 | Date |
---|---|---|
Shadowfacts | e9df08aa30 | |
Shadowfacts | 008354b74a | |
Shadowfacts | 1dffc67339 | |
Shadowfacts | 27518c68df | |
Shadowfacts | 2b739899a1 | |
Shadowfacts | 50b91f276b | |
Shadowfacts | 349c09f630 |
|
@ -5,6 +5,9 @@ import net.fabricmc.fabric.api.registry.CommandRegistry
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.server.command.CommandManager
|
import net.minecraft.server.command.CommandManager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
object ASMR: ModInitializer {
|
object ASMR: ModInitializer {
|
||||||
|
|
||||||
override fun onInitialize() {
|
override fun onInitialize() {
|
||||||
|
|
|
@ -2,10 +2,15 @@ package net.shadowfacts.asmr
|
||||||
|
|
||||||
import net.shadowfacts.kiwidsl.dsl
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
import net.shadowfacts.shadowui.Screen
|
import net.shadowfacts.shadowui.Screen
|
||||||
import net.shadowfacts.shadowui.View
|
import net.shadowfacts.shadowui.view.View
|
||||||
import net.shadowfacts.shadowui.Window
|
import net.shadowfacts.shadowui.Window
|
||||||
|
import net.shadowfacts.shadowui.geometry.Size
|
||||||
import net.shadowfacts.shadowui.util.Color
|
import net.shadowfacts.shadowui.util.Color
|
||||||
|
import net.shadowfacts.shadowui.view.Label
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
class TestScreen: Screen() {
|
class TestScreen: Screen() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -22,6 +27,10 @@ class TestScreen: Screen() {
|
||||||
val purple = green.addSubview(View().apply {
|
val purple = green.addSubview(View().apply {
|
||||||
backgroundColor = Color(0x800080)
|
backgroundColor = Color(0x800080)
|
||||||
})
|
})
|
||||||
|
purple.intrinsicContentSize = Size(width = 150.0, height = 150.0)
|
||||||
|
val label = purple.addSubview(Label("Hello, world!").apply {
|
||||||
|
textColor = Color.WHITE
|
||||||
|
})
|
||||||
|
|
||||||
solver.dsl {
|
solver.dsl {
|
||||||
red.leftAnchor equalTo 0
|
red.leftAnchor equalTo 0
|
||||||
|
@ -39,10 +48,13 @@ class TestScreen: Screen() {
|
||||||
blue.topAnchor equalTo (green.topAnchor + green.heightAnchor)
|
blue.topAnchor equalTo (green.topAnchor + green.heightAnchor)
|
||||||
blue.heightAnchor equalTo 50
|
blue.heightAnchor equalTo 50
|
||||||
|
|
||||||
purple.widthAnchor equalTo 100
|
// purple.widthAnchor equalTo 100
|
||||||
purple.heightAnchor equalTo 100
|
// purple.heightAnchor equalTo 100
|
||||||
purple.centerXAnchor equalTo green.centerXAnchor
|
purple.centerXAnchor equalTo green.centerXAnchor
|
||||||
purple.centerYAnchor equalTo green.centerYAnchor
|
purple.centerYAnchor equalTo green.centerYAnchor
|
||||||
|
|
||||||
|
label.centerXAnchor equalTo purple.centerXAnchor
|
||||||
|
label.centerYAnchor equalTo purple.centerYAnchor
|
||||||
}
|
}
|
||||||
|
|
||||||
layout()
|
layout()
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package net.shadowfacts.shadowui
|
package net.shadowfacts.shadowui
|
||||||
|
|
||||||
|
import net.shadowfacts.shadowui.view.View
|
||||||
import no.birkett.kiwi.Variable
|
import no.birkett.kiwi.Variable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
class LayoutVariable(val owner: View, val property: String): Variable("LayoutVariable") {
|
class LayoutVariable(val owner: View, val property: String): Variable("LayoutVariable") {
|
||||||
|
|
||||||
override fun getName() = "$owner.$property"
|
override fun getName() = "$owner.$property"
|
||||||
|
|
|
@ -5,6 +5,9 @@ import net.minecraft.network.chat.TextComponent
|
||||||
import net.shadowfacts.shadowui.geometry.Point
|
import net.shadowfacts.shadowui.geometry.Point
|
||||||
import no.birkett.kiwi.Solver
|
import no.birkett.kiwi.Solver
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
open class Screen: Screen(TextComponent("Screen")) {
|
open class Screen: Screen(TextComponent("Screen")) {
|
||||||
|
|
||||||
val windows = mutableListOf<Window>()
|
val windows = mutableListOf<Window>()
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package net.shadowfacts.shadowui
|
package net.shadowfacts.shadowui
|
||||||
|
|
||||||
import net.shadowfacts.shadowui.geometry.Point
|
import net.shadowfacts.shadowui.geometry.Point
|
||||||
|
import net.shadowfacts.shadowui.view.View
|
||||||
import no.birkett.kiwi.Solver
|
import no.birkett.kiwi.Solver
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
class Window {
|
class Window {
|
||||||
|
|
||||||
var solver = Solver()
|
var solver = Solver()
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package net.shadowfacts.shadowui.geometry
|
package net.shadowfacts.shadowui.geometry
|
||||||
|
|
||||||
class Point(val x: Double, val y: Double) {
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
data class Point(val x: Double, val y: Double) {
|
||||||
|
|
||||||
constructor(x: Int, y: Int): this(x.toDouble(), y.toDouble())
|
constructor(x: Int, y: Int): this(x.toDouble(), y.toDouble())
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,33 @@
|
||||||
package net.shadowfacts.shadowui.geometry
|
package net.shadowfacts.shadowui.geometry
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
data class Rect(val left: Double, val top: Double, val width: Double, val height: Double) {
|
data class Rect(val left: Double, val top: Double, val width: Double, val height: Double) {
|
||||||
|
|
||||||
val right: Double
|
val right: Double by lazy {
|
||||||
get() = left + width
|
left + width
|
||||||
val bottom: Double
|
}
|
||||||
get() = top + height
|
val bottom: Double by lazy {
|
||||||
|
top + height
|
||||||
|
}
|
||||||
|
|
||||||
val midX: Double
|
val midX: Double by lazy {
|
||||||
get() = left + width / 2
|
left + width / 2
|
||||||
val midY: Double
|
}
|
||||||
get() = top + height / 2
|
val midY: Double by lazy {
|
||||||
|
top + height / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
val origin: Point by lazy {
|
||||||
|
Point(left, top)
|
||||||
|
}
|
||||||
|
val center: Point by lazy {
|
||||||
|
Point(midX, midY)
|
||||||
|
}
|
||||||
|
|
||||||
|
val size: Size by lazy {
|
||||||
|
Size(width, height)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package net.shadowfacts.shadowui.geometry
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
data class Size(val width: Double, val height: Double)
|
|
@ -1,5 +1,8 @@
|
||||||
package net.shadowfacts.shadowui.util
|
package net.shadowfacts.shadowui.util
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
data class Color(val red: Int, val green: Int, val blue: Int, val alpha: Int = 255) {
|
data class Color(val red: Int, val green: Int, val blue: Int, val alpha: Int = 255) {
|
||||||
|
|
||||||
constructor(rgb: Int, alpha: Int = 255): this(rgb shr 16, (rgb shr 8) and 255, rgb and 255, alpha)
|
constructor(rgb: Int, alpha: Int = 255): this(rgb shr 16, (rgb shr 8) and 255, rgb and 255, alpha)
|
||||||
|
@ -7,4 +10,10 @@ data class Color(val red: Int, val green: Int, val blue: Int, val alpha: Int = 2
|
||||||
val argb: Int
|
val argb: Int
|
||||||
get() = ((alpha and 255) shl 24) or ((red and 255) shl 16) or ((green and 255) shl 8) or (blue and 255)
|
get() = ((alpha and 255) shl 24) or ((red and 255) shl 16) or ((green and 255) shl 8) or (blue and 255)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val CLEAR = Color(0, alpha = 0)
|
||||||
|
val WHITE = Color(0xffffff)
|
||||||
|
val BLACK = Color(0)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,6 +3,9 @@ package net.shadowfacts.shadowui.util
|
||||||
import net.minecraft.client.gui.DrawableHelper
|
import net.minecraft.client.gui.DrawableHelper
|
||||||
import net.shadowfacts.shadowui.geometry.Rect
|
import net.shadowfacts.shadowui.geometry.Rect
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
object RenderHelper {
|
object RenderHelper {
|
||||||
|
|
||||||
fun fill(rect: Rect, color: Color) {
|
fun fill(rect: Rect, color: Color) {
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package net.shadowfacts.shadowui.view
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient
|
||||||
|
import net.minecraft.client.font.TextRenderer
|
||||||
|
import net.shadowfacts.shadowui.geometry.Size
|
||||||
|
import net.shadowfacts.shadowui.util.Color
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class Label(text: String): View() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val textRenderer: TextRenderer
|
||||||
|
get() = MinecraftClient.getInstance().textRenderer
|
||||||
|
}
|
||||||
|
|
||||||
|
var text: String = text
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
updateIntrinsicContentSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
var textColor = Color(0x404040)
|
||||||
|
|
||||||
|
override fun wasAdded() {
|
||||||
|
super.wasAdded()
|
||||||
|
|
||||||
|
updateIntrinsicContentSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateIntrinsicContentSize() {
|
||||||
|
val width = textRenderer.getStringWidth(text)
|
||||||
|
val height = textRenderer.fontHeight
|
||||||
|
intrinsicContentSize = Size(width.toDouble(), height.toDouble())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawContent() {
|
||||||
|
textRenderer.draw(text, 0f, 0f, textColor.argb)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,13 +1,19 @@
|
||||||
package net.shadowfacts.shadowui
|
package net.shadowfacts.shadowui.view
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.GlStateManager
|
import com.mojang.blaze3d.platform.GlStateManager
|
||||||
import net.shadowfacts.kiwidsl.dsl
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
|
import net.shadowfacts.shadowui.LayoutVariable
|
||||||
import net.shadowfacts.shadowui.geometry.Rect
|
import net.shadowfacts.shadowui.geometry.Rect
|
||||||
|
import net.shadowfacts.shadowui.geometry.Size
|
||||||
import net.shadowfacts.shadowui.util.Color
|
import net.shadowfacts.shadowui.util.Color
|
||||||
import net.shadowfacts.shadowui.util.RenderHelper
|
import net.shadowfacts.shadowui.util.RenderHelper
|
||||||
|
import no.birkett.kiwi.Constraint
|
||||||
import no.birkett.kiwi.Solver
|
import no.birkett.kiwi.Solver
|
||||||
|
|
||||||
class View {
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
open class View {
|
||||||
|
|
||||||
lateinit var solver: Solver
|
lateinit var solver: Solver
|
||||||
|
|
||||||
|
@ -26,7 +32,15 @@ class View {
|
||||||
// The rectangle for this view in its own coordinate system.
|
// The rectangle for this view in its own coordinate system.
|
||||||
lateinit var bounds: Rect
|
lateinit var bounds: Rect
|
||||||
|
|
||||||
var backgroundColor = Color(0xff0000)
|
var intrinsicContentSize: Size? = null
|
||||||
|
set(value) {
|
||||||
|
updateIntrinsicContentSizeConstraints(intrinsicContentSize, value)
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
private var intrinsicContentSizeWidthConstraint: Constraint? = null
|
||||||
|
private var intrinsicContentSizeHeightConstraint: Constraint? = null
|
||||||
|
|
||||||
|
var backgroundColor = Color.CLEAR
|
||||||
|
|
||||||
var parent: View? = null
|
var parent: View? = null
|
||||||
val subviews = mutableListOf<View>()
|
val subviews = mutableListOf<View>()
|
||||||
|
@ -41,11 +55,11 @@ class View {
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
fun wasAdded() {
|
open fun wasAdded() {
|
||||||
createInternalConstraints()
|
createInternalConstraints()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createInternalConstraints() {
|
open fun createInternalConstraints() {
|
||||||
solver.dsl {
|
solver.dsl {
|
||||||
rightAnchor equalTo (leftAnchor + widthAnchor)
|
rightAnchor equalTo (leftAnchor + widthAnchor)
|
||||||
bottomAnchor equalTo (topAnchor + heightAnchor)
|
bottomAnchor equalTo (topAnchor + heightAnchor)
|
||||||
|
@ -54,7 +68,20 @@ class View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun didLayout() {
|
private fun updateIntrinsicContentSizeConstraints(old: Size?, new: Size?) {
|
||||||
|
if (old != null) {
|
||||||
|
solver.removeConstraint(intrinsicContentSizeWidthConstraint!!)
|
||||||
|
solver.removeConstraint(intrinsicContentSizeHeightConstraint!!)
|
||||||
|
}
|
||||||
|
if (new != null) {
|
||||||
|
solver.dsl {
|
||||||
|
this@View.intrinsicContentSizeWidthConstraint = (widthAnchor.equalTo(new.width, strength = WEAK))
|
||||||
|
this@View.intrinsicContentSizeHeightConstraint = (heightAnchor.equalTo(new.height, strength = WEAK))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun didLayout() {
|
||||||
subviews.forEach(View::didLayout)
|
subviews.forEach(View::didLayout)
|
||||||
|
|
||||||
val parentLeft = parent?.leftAnchor?.value ?: 0.0
|
val parentLeft = parent?.leftAnchor?.value ?: 0.0
|
||||||
|
@ -76,6 +103,6 @@ class View {
|
||||||
GlStateManager.popMatrix()
|
GlStateManager.popMatrix()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun drawContent() {}
|
open fun drawContent() {}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package net.shadowfacts.shadowui
|
||||||
|
|
||||||
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
|
import net.shadowfacts.shadowui.geometry.Size
|
||||||
|
import net.shadowfacts.shadowui.view.View
|
||||||
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class WindowTests {
|
||||||
|
|
||||||
|
lateinit var window: Window
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun setup() {
|
||||||
|
window = Window()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testConstraintToConstant() {
|
||||||
|
val view = window.addView(View())
|
||||||
|
window.solver.dsl {
|
||||||
|
view.leftAnchor equalTo 100
|
||||||
|
view.rightAnchor equalTo 200
|
||||||
|
|
||||||
|
view.topAnchor equalTo 100
|
||||||
|
view.heightAnchor equalTo 200
|
||||||
|
}
|
||||||
|
window.layout()
|
||||||
|
|
||||||
|
assertEquals(100.0, view.widthAnchor.value)
|
||||||
|
assertEquals(300.0, view.bottomAnchor.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testConstraintToView() {
|
||||||
|
val one = window.addView(View())
|
||||||
|
val two = window.addView(View())
|
||||||
|
window.solver.dsl {
|
||||||
|
one.leftAnchor equalTo 0
|
||||||
|
one.widthAnchor equalTo 100
|
||||||
|
|
||||||
|
one.topAnchor equalTo 0
|
||||||
|
one.heightAnchor equalTo 200
|
||||||
|
|
||||||
|
two.leftAnchor equalTo one.rightAnchor
|
||||||
|
two.rightAnchor equalTo 400
|
||||||
|
|
||||||
|
two.topAnchor equalTo one.bottomAnchor
|
||||||
|
two.heightAnchor equalTo one.heightAnchor
|
||||||
|
}
|
||||||
|
window.layout()
|
||||||
|
|
||||||
|
assertEquals(100.0, two.leftAnchor.value)
|
||||||
|
assertEquals(300.0, two.widthAnchor.value)
|
||||||
|
|
||||||
|
assertEquals(200.0, two.topAnchor.value)
|
||||||
|
assertEquals(400.0, two.bottomAnchor.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntrinsicContentSize() {
|
||||||
|
val view = window.addView(View()).apply {
|
||||||
|
intrinsicContentSize = Size(100.0, 200.0)
|
||||||
|
}
|
||||||
|
window.solver.dsl {
|
||||||
|
view.leftAnchor equalTo 0
|
||||||
|
view.topAnchor equalTo 100
|
||||||
|
}
|
||||||
|
window.layout()
|
||||||
|
|
||||||
|
assertEquals(100.0, view.widthAnchor.value)
|
||||||
|
assertEquals(100.0, view.rightAnchor.value)
|
||||||
|
|
||||||
|
assertEquals(200.0, view.heightAnchor.value)
|
||||||
|
assertEquals(300.0, view.bottomAnchor.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package net.shadowfacts.shadowui.geometry
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class RectTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testTrailingEdges() {
|
||||||
|
val rect = Rect(25.0, 50.0, 100.0, 200.0)
|
||||||
|
assertEquals(125.0, rect.right)
|
||||||
|
assertEquals(250.0, rect.bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCenter() {
|
||||||
|
val rect = Rect(25.0, 50.0, 100.0, 200.0)
|
||||||
|
assertEquals(75.0, rect.midX)
|
||||||
|
assertEquals(150.0, rect.midY)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPoints() {
|
||||||
|
val rect = Rect(25.0, 50.0, 100.0, 200.0)
|
||||||
|
assertEquals(Point(25.0, 50.0), rect.origin)
|
||||||
|
assertEquals(Point(75.0, 150.0), rect.center)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSize() {
|
||||||
|
val rect = Rect(25.0, 50.0, 100.0, 200.0)
|
||||||
|
assertEquals(Size(100.0, 200.0), rect.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package net.shadowfacts.shadowui.util
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class ColorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun fromRGB() {
|
||||||
|
val color = Color(0x123456)
|
||||||
|
assertEquals(0x12, color.red)
|
||||||
|
assertEquals(0x34, color.green)
|
||||||
|
assertEquals(0x56, color.blue)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toARGB() {
|
||||||
|
val color = Color(red = 0x12, green = 0x34, blue = 0x56, alpha = 0x78)
|
||||||
|
assertEquals(0x78123456, color.argb)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue