Compare commits

...

7 Commits

Author SHA1 Message Date
Shadowfacts e9df08aa30
Move View class to view package 2019-06-22 11:17:56 -04:00
Shadowfacts 008354b74a
Add Window layout unit tests 2019-06-22 11:17:29 -04:00
Shadowfacts 1dffc67339
Add Rect unit tests 2019-06-22 11:06:39 -04:00
Shadowfacts 27518c68df
Add Color unit tests 2019-06-22 11:02:21 -04:00
Shadowfacts 2b739899a1
Add missing JavaDoc headers 2019-06-22 10:59:18 -04:00
Shadowfacts 50b91f276b
Add Label 2019-06-22 10:56:12 -04:00
Shadowfacts 349c09f630
Add View intrinsic content size 2019-06-22 10:21:29 -04:00
15 changed files with 299 additions and 19 deletions

View File

@ -5,6 +5,9 @@ import net.fabricmc.fabric.api.registry.CommandRegistry
import net.minecraft.client.MinecraftClient
import net.minecraft.server.command.CommandManager
/**
* @author shadowfacts
*/
object ASMR: ModInitializer {
override fun onInitialize() {

View File

@ -2,10 +2,15 @@ package net.shadowfacts.asmr
import net.shadowfacts.kiwidsl.dsl
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.geometry.Size
import net.shadowfacts.shadowui.util.Color
import net.shadowfacts.shadowui.view.Label
/**
* @author shadowfacts
*/
class TestScreen: Screen() {
init {
@ -22,6 +27,10 @@ class TestScreen: Screen() {
val purple = green.addSubview(View().apply {
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 {
red.leftAnchor equalTo 0
@ -39,10 +48,13 @@ class TestScreen: Screen() {
blue.topAnchor equalTo (green.topAnchor + green.heightAnchor)
blue.heightAnchor equalTo 50
purple.widthAnchor equalTo 100
purple.heightAnchor equalTo 100
// purple.widthAnchor equalTo 100
// purple.heightAnchor equalTo 100
purple.centerXAnchor equalTo green.centerXAnchor
purple.centerYAnchor equalTo green.centerYAnchor
label.centerXAnchor equalTo purple.centerXAnchor
label.centerYAnchor equalTo purple.centerYAnchor
}
layout()

View File

@ -1,7 +1,11 @@
package net.shadowfacts.shadowui
import net.shadowfacts.shadowui.view.View
import no.birkett.kiwi.Variable
/**
* @author shadowfacts
*/
class LayoutVariable(val owner: View, val property: String): Variable("LayoutVariable") {
override fun getName() = "$owner.$property"

View File

@ -5,6 +5,9 @@ import net.minecraft.network.chat.TextComponent
import net.shadowfacts.shadowui.geometry.Point
import no.birkett.kiwi.Solver
/**
* @author shadowfacts
*/
open class Screen: Screen(TextComponent("Screen")) {
val windows = mutableListOf<Window>()

View File

@ -1,8 +1,12 @@
package net.shadowfacts.shadowui
import net.shadowfacts.shadowui.geometry.Point
import net.shadowfacts.shadowui.view.View
import no.birkett.kiwi.Solver
/**
* @author shadowfacts
*/
class Window {
var solver = Solver()

View File

@ -1,6 +1,9 @@
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())

View File

@ -1,15 +1,33 @@
package net.shadowfacts.shadowui.geometry
/**
* @author shadowfacts
*/
data class Rect(val left: Double, val top: Double, val width: Double, val height: Double) {
val right: Double
get() = left + width
val bottom: Double
get() = top + height
val right: Double by lazy {
left + width
}
val bottom: Double by lazy {
top + height
}
val midX: Double
get() = left + width / 2
val midY: Double
get() = top + height / 2
val midX: Double by lazy {
left + width / 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)
}
}

View File

@ -0,0 +1,6 @@
package net.shadowfacts.shadowui.geometry
/**
* @author shadowfacts
*/
data class Size(val width: Double, val height: Double)

View File

@ -1,5 +1,8 @@
package net.shadowfacts.shadowui.util
/**
* @author shadowfacts
*/
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)
@ -7,4 +10,10 @@ data class Color(val red: Int, val green: Int, val blue: Int, val alpha: Int = 2
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)
companion object {
val CLEAR = Color(0, alpha = 0)
val WHITE = Color(0xffffff)
val BLACK = Color(0)
}
}

View File

@ -3,6 +3,9 @@ package net.shadowfacts.shadowui.util
import net.minecraft.client.gui.DrawableHelper
import net.shadowfacts.shadowui.geometry.Rect
/**
* @author shadowfacts
*/
object RenderHelper {
fun fill(rect: Rect, color: Color) {

View File

@ -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)
}
}

View File

@ -1,13 +1,19 @@
package net.shadowfacts.shadowui
package net.shadowfacts.shadowui.view
import com.mojang.blaze3d.platform.GlStateManager
import net.shadowfacts.kiwidsl.dsl
import net.shadowfacts.shadowui.LayoutVariable
import net.shadowfacts.shadowui.geometry.Rect
import net.shadowfacts.shadowui.geometry.Size
import net.shadowfacts.shadowui.util.Color
import net.shadowfacts.shadowui.util.RenderHelper
import no.birkett.kiwi.Constraint
import no.birkett.kiwi.Solver
class View {
/**
* @author shadowfacts
*/
open class View {
lateinit var solver: Solver
@ -26,7 +32,15 @@ class View {
// The rectangle for this view in its own coordinate system.
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
val subviews = mutableListOf<View>()
@ -41,11 +55,11 @@ class View {
return view
}
fun wasAdded() {
open fun wasAdded() {
createInternalConstraints()
}
fun createInternalConstraints() {
open fun createInternalConstraints() {
solver.dsl {
rightAnchor equalTo (leftAnchor + widthAnchor)
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)
val parentLeft = parent?.leftAnchor?.value ?: 0.0
@ -76,6 +103,6 @@ class View {
GlStateManager.popMatrix()
}
fun drawContent() {}
open fun drawContent() {}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}