diff --git a/src/main/kotlin/net/shadowfacts/asmr/ASMR.kt b/src/main/kotlin/net/shadowfacts/asmr/ASMR.kt index b3f7fc7..c20d431 100644 --- a/src/main/kotlin/net/shadowfacts/asmr/ASMR.kt +++ b/src/main/kotlin/net/shadowfacts/asmr/ASMR.kt @@ -1,11 +1,27 @@ package net.shadowfacts.asmr import net.fabricmc.api.ModInitializer +import net.fabricmc.fabric.api.registry.CommandRegistry +import net.minecraft.client.MinecraftClient +import net.minecraft.server.command.CommandManager object ASMR: ModInitializer { override fun onInitialize() { println("hello fabric") + + CommandRegistry.INSTANCE.register(false) { dispatcher -> + val command = CommandManager.literal("uitest").executes { + try { + MinecraftClient.getInstance().openScreen(UITest()) + } catch (e: Throwable) { + e.printStackTrace() + } + 1 + } + + dispatcher.register(command) + } } } \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/asmr/UITest.kt b/src/main/kotlin/net/shadowfacts/asmr/UITest.kt new file mode 100644 index 0000000..5c682af --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/asmr/UITest.kt @@ -0,0 +1,54 @@ +package net.shadowfacts.asmr + +import net.shadowfacts.kiwidsl.dsl +import net.shadowfacts.shadowui.UIScreen +import net.shadowfacts.shadowui.UIView +import net.shadowfacts.shadowui.util.Color + +class UITest: UIScreen() { + + init { + val red = UIView().apply { + backgroundColor = Color(0xff0000) + addView(this) + } + val green = UIView().apply { + backgroundColor = Color(0x00ff00) + addView(this) + } + val blue = UIView().apply { + backgroundColor = Color(0x0000ff) + addView(this) + } + + val purple = UIView().apply { + backgroundColor = Color(0x800080) + green.addSubview(this) + } + + solver.dsl { + red.leftAnchor equalTo 0 + red.widthAnchor equalTo 200 + red.topAnchor equalTo 0 + red.heightAnchor equalTo 100 + + green.leftAnchor equalTo (red.leftAnchor + red.widthAnchor + 20) + green.widthAnchor equalTo red.widthAnchor + green.topAnchor equalTo 0 + green.heightAnchor equalTo (red.heightAnchor + 100) + + blue.leftAnchor equalTo green.leftAnchor + blue.widthAnchor equalTo green.widthAnchor + blue.topAnchor equalTo (green.topAnchor + green.heightAnchor) + blue.heightAnchor equalTo 50 + + purple.widthAnchor equalTo 100 + purple.heightAnchor equalTo 100 + purple.centerXAnchor equalTo green.centerXAnchor + purple.centerYAnchor equalTo green.centerYAnchor + } + + layout() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/shadowui/LayoutVariable.kt b/src/main/kotlin/net/shadowfacts/shadowui/LayoutVariable.kt new file mode 100644 index 0000000..deff55b --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/shadowui/LayoutVariable.kt @@ -0,0 +1,11 @@ +package net.shadowfacts.shadowui + +import no.birkett.kiwi.Variable + +class LayoutVariable(val owner: UIView, val property: String): Variable("LayoutVariable") { + + override fun getName() = "$owner.$property" + + override fun toString() = "LayoutVariable(name=$name, value=$value)" + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/shadowui/UIScreen.kt b/src/main/kotlin/net/shadowfacts/shadowui/UIScreen.kt new file mode 100644 index 0000000..d500acc --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/shadowui/UIScreen.kt @@ -0,0 +1,28 @@ +package net.shadowfacts.shadowui + +import net.minecraft.client.gui.screen.Screen +import net.minecraft.network.chat.TextComponent +import no.birkett.kiwi.Solver + +open class UIScreen: Screen(TextComponent("UIScreen")) { + + val solver = Solver() + + val views = mutableListOf() + + fun addView(view: UIView) { + views.add(view) + view.solver = solver + view.wasAdded() + } + + fun layout() { + solver.updateVariables() + views.forEach(UIView::didLayout) + } + + override fun render(mouseX: Int, mouseY: Int, delta: Float) { + views.forEach(UIView::draw) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/shadowui/UIView.kt b/src/main/kotlin/net/shadowfacts/shadowui/UIView.kt new file mode 100644 index 0000000..78e0028 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/shadowui/UIView.kt @@ -0,0 +1,79 @@ +package net.shadowfacts.shadowui + +import com.mojang.blaze3d.platform.GlStateManager +import net.shadowfacts.kiwidsl.dsl +import net.shadowfacts.shadowui.geometry.UIRect +import net.shadowfacts.shadowui.util.Color +import net.shadowfacts.shadowui.util.RenderHelper +import no.birkett.kiwi.Solver + +class UIView { + + lateinit var solver: Solver + + // in the coordinate system of the screen + val leftAnchor = LayoutVariable(this, "left") + val rightAnchor = LayoutVariable(this, "right") + val topAnchor = LayoutVariable(this, "top") + val bottomAnchor = LayoutVariable(this, "bottom") + val widthAnchor = LayoutVariable(this, "width") + val heightAnchor = LayoutVariable(this, "height") + val centerXAnchor = LayoutVariable(this, "centerX") + val centerYAnchor = LayoutVariable(this, "centerY") + + // The rectangle for this view in the coordinate system of the parent view. + lateinit var frame: UIRect + // The rectangle for this view in its own coordinate system. + lateinit var bounds: UIRect + + var backgroundColor = Color(0xff0000) + + var parent: UIView? = null + val subviews = mutableListOf() + + fun addSubview(view: UIView) { + subviews.add(view) + view.parent = this + view.solver = solver + + view.wasAdded() + } + + fun wasAdded() { + createInternalConstraints() + } + + fun createInternalConstraints() { + solver.dsl { + rightAnchor equalTo (leftAnchor + widthAnchor) + bottomAnchor equalTo (topAnchor + heightAnchor) + centerXAnchor equalTo (leftAnchor + widthAnchor / 2) + centerYAnchor equalTo (topAnchor + heightAnchor / 2) + } + } + + fun didLayout() { + subviews.forEach(UIView::didLayout) + + val parentLeft = parent?.leftAnchor?.value ?: 0.0 + val parentTop = parent?.topAnchor?.value ?: 0.0 + frame = UIRect(leftAnchor.value - parentLeft, topAnchor.value - parentTop, widthAnchor.value, heightAnchor.value) + bounds = UIRect(0.0, 0.0, widthAnchor.value, heightAnchor.value) + } + + fun draw() { + GlStateManager.pushMatrix() + GlStateManager.translated(frame.left, frame.top, 0.0) + + RenderHelper.fill(bounds, backgroundColor) + + drawContent() + + subviews.forEach(UIView::draw) + + GlStateManager.popMatrix() + } + + fun drawContent() {} + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/shadowui/geometry/UIRect.kt b/src/main/kotlin/net/shadowfacts/shadowui/geometry/UIRect.kt new file mode 100644 index 0000000..6d3876b --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/shadowui/geometry/UIRect.kt @@ -0,0 +1,15 @@ +package net.shadowfacts.shadowui.geometry + +data class UIRect(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 midX: Double + get() = left + width / 2 + val midY: Double + get() = top + height / 2 + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/shadowui/util/Color.kt b/src/main/kotlin/net/shadowfacts/shadowui/util/Color.kt new file mode 100644 index 0000000..7dcd10b --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/shadowui/util/Color.kt @@ -0,0 +1,10 @@ +package net.shadowfacts.shadowui.util + +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) + + 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) + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/shadowui/util/RenderHelper.kt b/src/main/kotlin/net/shadowfacts/shadowui/util/RenderHelper.kt new file mode 100644 index 0000000..914e0f3 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/shadowui/util/RenderHelper.kt @@ -0,0 +1,12 @@ +package net.shadowfacts.shadowui.util + +import net.minecraft.client.gui.DrawableHelper +import net.shadowfacts.shadowui.geometry.UIRect + +object RenderHelper { + + fun fill(rect: UIRect, color: Color) { + DrawableHelper.fill(rect.left.toInt(), rect.top.toInt(), rect.right.toInt(), rect.bottom.toInt(), color.argb) + } + +} \ No newline at end of file