Cacao: Add text field
This commit is contained in:
parent
277bcb71ee
commit
9e3366cbfb
|
@ -6,9 +6,11 @@ import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.minecraft.sound.SoundEvents
|
import net.minecraft.sound.SoundEvents
|
||||||
import net.minecraft.text.LiteralText
|
import net.minecraft.text.LiteralText
|
||||||
import net.shadowfacts.cacao.geometry.Point
|
import net.shadowfacts.cacao.geometry.Point
|
||||||
|
import net.shadowfacts.cacao.util.KeyModifiers
|
||||||
import net.shadowfacts.cacao.util.MouseButton
|
import net.shadowfacts.cacao.util.MouseButton
|
||||||
import net.shadowfacts.cacao.util.RenderHelper
|
import net.shadowfacts.cacao.util.RenderHelper
|
||||||
import net.shadowfacts.cacao.window.Window
|
import net.shadowfacts.cacao.window.Window
|
||||||
|
import org.lwjgl.glfw.GLFW
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,6 +57,7 @@ open class CacaoScreen: Screen(LiteralText("CacaoScreen")), AbstractCacaoScreen
|
||||||
*/
|
*/
|
||||||
override fun removeWindow(window: Window) {
|
override fun removeWindow(window: Window) {
|
||||||
_windows.remove(window)
|
_windows.remove(window)
|
||||||
|
// todo: VC callbacks
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
|
@ -65,6 +68,17 @@ open class CacaoScreen: Screen(LiteralText("CacaoScreen")), AbstractCacaoScreen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onClose() {
|
||||||
|
super.onClose()
|
||||||
|
|
||||||
|
windows.forEach {
|
||||||
|
// todo: VC callbacks
|
||||||
|
|
||||||
|
// resign the current first responder (if any)
|
||||||
|
it.firstResponder = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
// workaround this.minecraft sometimes being null causing a crash
|
// workaround this.minecraft sometimes being null causing a crash
|
||||||
|
@ -102,4 +116,35 @@ open class CacaoScreen: Screen(LiteralText("CacaoScreen")), AbstractCacaoScreen
|
||||||
return result == true
|
return result == true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
|
||||||
|
val modifiersSet by lazy { KeyModifiers(modifiers) }
|
||||||
|
if (findResponder { it.keyPressed(keyCode, modifiersSet) }) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.keyPressed(keyCode, scanCode, modifiers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyReleased(i: Int, j: Int, k: Int): Boolean {
|
||||||
|
return super.keyReleased(i, j, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun charTyped(char: Char, modifiers: Int): Boolean {
|
||||||
|
val modifiersSet by lazy { KeyModifiers(modifiers) }
|
||||||
|
if (findResponder { it.charTyped(char, modifiersSet) }) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.charTyped(char, modifiers)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findResponder(fn: (Responder) -> Boolean): Boolean {
|
||||||
|
var responder = windows.lastOrNull()?.firstResponder
|
||||||
|
while (responder != null) {
|
||||||
|
if (fn(responder)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
responder = responder.nextResponder
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package net.shadowfacts.cacao
|
||||||
|
|
||||||
|
import net.shadowfacts.cacao.util.KeyModifiers
|
||||||
|
import net.shadowfacts.cacao.window.Window
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
interface Responder {
|
||||||
|
|
||||||
|
val window: Window?
|
||||||
|
|
||||||
|
val isFirstResponder: Boolean
|
||||||
|
get() = window?.firstResponder === this
|
||||||
|
|
||||||
|
val nextResponder: Responder?
|
||||||
|
|
||||||
|
fun becomeFirstResponder() {
|
||||||
|
if (window == null) {
|
||||||
|
throw RuntimeException("Cannot become first responder while not in Window")
|
||||||
|
}
|
||||||
|
window!!.firstResponder = this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun didBecomeFirstResponder() {}
|
||||||
|
|
||||||
|
fun resignFirstResponder() {
|
||||||
|
if (window == null) {
|
||||||
|
throw RuntimeException("Cannot resign first responder while not in Window")
|
||||||
|
}
|
||||||
|
window!!.firstResponder = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun didResignFirstResponder() {}
|
||||||
|
|
||||||
|
fun charTyped(char: Char, modifiers: KeyModifiers): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun keyPressed(keyCode: Int, modifiers: KeyModifiers): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package net.shadowfacts.cacao.util
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class KeyModifiers(val value: Int) {
|
||||||
|
|
||||||
|
val shift: Boolean
|
||||||
|
get() = this[GLFW.GLFW_MOD_SHIFT]
|
||||||
|
|
||||||
|
val control: Boolean
|
||||||
|
get() = this[GLFW.GLFW_MOD_CONTROL]
|
||||||
|
|
||||||
|
val alt: Boolean
|
||||||
|
get() = this[GLFW.GLFW_MOD_ALT]
|
||||||
|
|
||||||
|
val command: Boolean
|
||||||
|
get() = this[GLFW.GLFW_MOD_SUPER]
|
||||||
|
|
||||||
|
val capsLock: Boolean
|
||||||
|
get() = this[GLFW.GLFW_MOD_CAPS_LOCK]
|
||||||
|
|
||||||
|
val numLock: Boolean
|
||||||
|
get() = this[GLFW.GLFW_MOD_NUM_LOCK]
|
||||||
|
|
||||||
|
private operator fun get(mod: Int): Boolean {
|
||||||
|
return (value and mod) == mod
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package net.shadowfacts.cacao.view
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.shadowfacts.kiwidsl.dsl
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
import net.shadowfacts.cacao.LayoutVariable
|
import net.shadowfacts.cacao.LayoutVariable
|
||||||
|
import net.shadowfacts.cacao.Responder
|
||||||
import net.shadowfacts.cacao.window.Window
|
import net.shadowfacts.cacao.window.Window
|
||||||
import net.shadowfacts.cacao.geometry.*
|
import net.shadowfacts.cacao.geometry.*
|
||||||
import net.shadowfacts.cacao.util.*
|
import net.shadowfacts.cacao.util.*
|
||||||
|
@ -19,14 +20,18 @@ import kotlin.collections.HashSet
|
||||||
*
|
*
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
open class View() {
|
open class View(): Responder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The window whose view hierarchy this view belongs to.
|
* The window whose view hierarchy this view belongs to.
|
||||||
* Not initialized until the root view in this hierarchy has been added to a hierarchy,
|
* Not initialized until the root view in this hierarchy has been added to a hierarchy,
|
||||||
* using it before that will throw a runtime exception.
|
* using it before that will throw a runtime exception.
|
||||||
*/
|
*/
|
||||||
var window: Window? = null
|
override var window: Window? = null
|
||||||
|
|
||||||
|
override val nextResponder: Responder?
|
||||||
|
// todo: should the view controller be a Responder?
|
||||||
|
get() = superview
|
||||||
|
|
||||||
private val solverDelegate = ObservableLateInitProperty<Solver> {
|
private val solverDelegate = ObservableLateInitProperty<Solver> {
|
||||||
for (v in subviews) {
|
for (v in subviews) {
|
||||||
|
@ -354,12 +359,25 @@ open class View() {
|
||||||
* @return Whether the mouse click was handled by this view or any subviews.
|
* @return Whether the mouse click was handled by this view or any subviews.
|
||||||
*/
|
*/
|
||||||
open fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
|
open fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
|
||||||
val view = subviewsAtPoint(point).maxByOrNull(View::zIndex)
|
val (inside, outside) = subviews.partition { point in it.frame }
|
||||||
|
val view = inside.maxByOrNull(View::zIndex)
|
||||||
|
var result = false
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
val pointInView = convert(point, to = view)
|
val pointInView = convert(point, to = view)
|
||||||
return view.mouseClicked(pointInView, mouseButton)
|
result = view.mouseClicked(pointInView, mouseButton)
|
||||||
|
}
|
||||||
|
for (v in outside) {
|
||||||
|
val pointInV = convert(point, to = v)
|
||||||
|
v.mouseClickedOutside(pointInV, mouseButton)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun mouseClickedOutside(point: Point, mouseButton: MouseButton) {
|
||||||
|
for (view in subviews) {
|
||||||
|
val pointInView = convert(point, to = view)
|
||||||
|
view.mouseClickedOutside(pointInView, mouseButton)
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mouseDragged(startPoint: Point, delta: Point, mouseButton: MouseButton): Boolean {
|
open fun mouseDragged(startPoint: Point, delta: Point, mouseButton: MouseButton): Boolean {
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
package net.shadowfacts.cacao.view.textfield
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient
|
||||||
|
import net.minecraft.client.gui.widget.TextFieldWidget
|
||||||
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
|
import net.minecraft.text.LiteralText
|
||||||
|
import net.shadowfacts.cacao.geometry.Point
|
||||||
|
import net.shadowfacts.cacao.util.Color
|
||||||
|
import net.shadowfacts.cacao.util.KeyModifiers
|
||||||
|
import net.shadowfacts.cacao.util.MouseButton
|
||||||
|
import net.shadowfacts.cacao.util.RenderHelper
|
||||||
|
import net.shadowfacts.cacao.view.View
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
|
||||||
|
initialText: String
|
||||||
|
): View() {
|
||||||
|
|
||||||
|
var handler: ((Impl) -> Unit)? = null
|
||||||
|
var disabled = false
|
||||||
|
|
||||||
|
val focused: Boolean
|
||||||
|
get() = isFirstResponder
|
||||||
|
|
||||||
|
var text: String
|
||||||
|
get() = minecraftWidget.text
|
||||||
|
set(value) {
|
||||||
|
minecraftWidget.text = value
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var originInWindow: Point
|
||||||
|
private var minecraftWidget = ProxyWidget()
|
||||||
|
|
||||||
|
init {
|
||||||
|
minecraftWidget.text = initialText
|
||||||
|
minecraftWidget.setTextPredicate { this.validate(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun validate(proposedText: String): Boolean
|
||||||
|
|
||||||
|
override fun didLayout() {
|
||||||
|
super.didLayout()
|
||||||
|
|
||||||
|
originInWindow = convert(bounds.origin, to = null)
|
||||||
|
|
||||||
|
// offset View dimensions by 1 on each side because TextFieldWidget draws the border outside its dimensions
|
||||||
|
minecraftWidget.x = originInWindow.x.toInt() + 1
|
||||||
|
minecraftWidget.y = originInWindow.y.toInt() + 1
|
||||||
|
minecraftWidget.width = bounds.width.toInt() - 2
|
||||||
|
minecraftWidget.height = bounds.height.toInt() - 2
|
||||||
|
|
||||||
|
// after dimensions change call setText on the widget to make sure its internal scroll position is up-to-date
|
||||||
|
minecraftWidget.text = text
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
||||||
|
RenderHelper.pushMatrix()
|
||||||
|
RenderHelper.translate(-originInWindow.x, -originInWindow.y)
|
||||||
|
|
||||||
|
val mouseXInWindow = (mouse.x + originInWindow.x).toInt()
|
||||||
|
val mouseYInWindow = (mouse.y + originInWindow.y).toInt()
|
||||||
|
minecraftWidget.render(matrixStack, mouseXInWindow, mouseYInWindow, delta)
|
||||||
|
|
||||||
|
RenderHelper.popMatrix()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
|
||||||
|
if (!disabled) {
|
||||||
|
if (focused) {
|
||||||
|
val mouseXInWindow = (point.x + originInWindow.x)
|
||||||
|
val mouseYInWindow = (point.y + originInWindow.y)
|
||||||
|
minecraftWidget.mouseClicked(mouseXInWindow, mouseYInWindow, mouseButton.ordinal)
|
||||||
|
} else {
|
||||||
|
becomeFirstResponder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// don't play sound when interacting with text field
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseClickedOutside(point: Point, mouseButton: MouseButton) {
|
||||||
|
if (focused) {
|
||||||
|
resignFirstResponder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun didBecomeFirstResponder() {
|
||||||
|
super.didBecomeFirstResponder()
|
||||||
|
minecraftWidget.setSelected(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun didResignFirstResponder() {
|
||||||
|
super.didResignFirstResponder()
|
||||||
|
minecraftWidget.setSelected(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun charTyped(char: Char, modifiers: KeyModifiers): Boolean {
|
||||||
|
val oldText = text
|
||||||
|
val result = minecraftWidget.charTyped(char, modifiers.value)
|
||||||
|
if (text != oldText) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
handler?.invoke(this as Impl)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyPressed(keyCode: Int, modifiers: KeyModifiers): Boolean {
|
||||||
|
val oldText = text
|
||||||
|
// scanCode isn't used by TextFieldWidget, hopefully this doesn't break :/
|
||||||
|
val result = minecraftWidget.keyPressed(keyCode, -1, modifiers.value)
|
||||||
|
if (text != oldText) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
handler?.invoke(this as Impl)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: label for the TextFieldWidget?
|
||||||
|
class ProxyWidget: TextFieldWidget(MinecraftClient.getInstance().textRenderer, 0, 0, 0, 0, LiteralText("")) {
|
||||||
|
// AbstractButtonWidget.height is protected
|
||||||
|
fun setHeight(height: Int) {
|
||||||
|
this.height = height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package net.shadowfacts.cacao.view.textfield
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class TextField(initialText: String): AbstractTextField<TextField>(initialText) {
|
||||||
|
constructor(initialText: String, handler: (TextField) -> Unit): this(initialText) {
|
||||||
|
this.handler = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun validate(proposedText: String): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package net.shadowfacts.cacao.window
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.shadowfacts.cacao.AbstractCacaoScreen
|
import net.shadowfacts.cacao.AbstractCacaoScreen
|
||||||
import net.shadowfacts.cacao.CacaoScreen
|
import net.shadowfacts.cacao.CacaoScreen
|
||||||
|
import net.shadowfacts.cacao.Responder
|
||||||
import net.shadowfacts.cacao.geometry.Point
|
import net.shadowfacts.cacao.geometry.Point
|
||||||
import net.shadowfacts.cacao.util.MouseButton
|
import net.shadowfacts.cacao.util.MouseButton
|
||||||
import net.shadowfacts.cacao.view.View
|
import net.shadowfacts.cacao.view.View
|
||||||
|
@ -73,6 +74,13 @@ open class Window(
|
||||||
*/
|
*/
|
||||||
val centerYAnchor = Variable("centerY")
|
val centerYAnchor = Variable("centerY")
|
||||||
|
|
||||||
|
var firstResponder: Responder? = null
|
||||||
|
set(value) {
|
||||||
|
field?.didResignFirstResponder()
|
||||||
|
field = value
|
||||||
|
field?.didBecomeFirstResponder()
|
||||||
|
}
|
||||||
|
|
||||||
// internal constraints that specify the window size based on the MC screen size
|
// internal constraints that specify the window size based on the MC screen size
|
||||||
// stored so that they can be removed when the screen is resized
|
// stored so that they can be removed when the screen is resized
|
||||||
private var widthConstraint: Constraint? = null
|
private var widthConstraint: Constraint? = null
|
||||||
|
|
|
@ -13,6 +13,7 @@ import net.shadowfacts.cacao.util.texture.NinePatchTexture
|
||||||
import net.shadowfacts.cacao.util.texture.Texture
|
import net.shadowfacts.cacao.util.texture.Texture
|
||||||
import net.shadowfacts.cacao.view.*
|
import net.shadowfacts.cacao.view.*
|
||||||
import net.shadowfacts.cacao.view.button.Button
|
import net.shadowfacts.cacao.view.button.Button
|
||||||
|
import net.shadowfacts.cacao.view.textfield.TextField
|
||||||
import net.shadowfacts.cacao.viewcontroller.TabViewController
|
import net.shadowfacts.cacao.viewcontroller.TabViewController
|
||||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||||
import net.shadowfacts.kiwidsl.dsl
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
|
@ -23,70 +24,78 @@ import net.shadowfacts.kiwidsl.dsl
|
||||||
class TestCacaoScreen: CacaoScreen() {
|
class TestCacaoScreen: CacaoScreen() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// val viewController = object: ViewController() {
|
|
||||||
// override fun loadView() {
|
|
||||||
// view = View()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun viewDidLoad() {
|
|
||||||
// super.viewDidLoad()
|
|
||||||
//
|
|
||||||
// val stack = view.addSubview(StackView(Axis.VERTICAL, StackView.Distribution.CENTER, spacing = 4.0)).apply {
|
|
||||||
// backgroundColor = Color.WHITE
|
|
||||||
// }
|
|
||||||
// val birch = stack.addArrangedSubview(TextureView(Texture(Identifier("textures/block/birch_log_top.png"), 0, 0, 16, 16))).apply {
|
|
||||||
// intrinsicContentSize = Size(50.0, 50.0)
|
|
||||||
// }
|
|
||||||
// val ninePatch = stack.addArrangedSubview(NinePatchView(NinePatchTexture.PANEL_BG)).apply {
|
|
||||||
// intrinsicContentSize = Size(75.0, 100.0)
|
|
||||||
// }
|
|
||||||
// val red = stack.addArrangedSubview(View()).apply {
|
|
||||||
// intrinsicContentSize = Size(50.0, 50.0)
|
|
||||||
// backgroundColor = Color.RED
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val label = Label(LiteralText("Test"), wrappingMode = Label.WrappingMode.NO_WRAP).apply {
|
|
||||||
//// textColor = Color.BLACK
|
|
||||||
// }
|
|
||||||
//// stack.addArrangedSubview(label)
|
|
||||||
// val button = red.addSubview(Button(label))
|
|
||||||
//
|
|
||||||
// view.solver.dsl {
|
|
||||||
// stack.topAnchor equalTo 0
|
|
||||||
// stack.centerXAnchor equalTo window!!.centerXAnchor
|
|
||||||
// stack.widthAnchor equalTo 100
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// button.centerXAnchor equalTo red.centerXAnchor
|
|
||||||
// button.centerYAnchor equalTo red.centerYAnchor
|
|
||||||
//// label.heightAnchor equalTo 9
|
|
||||||
// button.heightAnchor equalTo 20
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// addWindow(Window(viewController))
|
|
||||||
|
|
||||||
val viewController = object: ViewController() {
|
val viewController = object: ViewController() {
|
||||||
|
override fun loadView() {
|
||||||
|
view = View()
|
||||||
|
}
|
||||||
|
|
||||||
override fun viewDidLoad() {
|
override fun viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
val tabs = arrayOf(
|
val stack = view.addSubview(StackView(Axis.VERTICAL, StackView.Distribution.CENTER, spacing = 4.0)).apply {
|
||||||
Tab(Label("A"), AViewController()),
|
backgroundColor = Color.WHITE
|
||||||
Tab(Label("B"), BViewController()),
|
}
|
||||||
)
|
val birch = stack.addArrangedSubview(TextureView(Texture(Identifier("textures/block/birch_log_top.png"), 0, 0, 16, 16))).apply {
|
||||||
val tabVC = TabViewController(tabs)
|
intrinsicContentSize = Size(50.0, 50.0)
|
||||||
embedChild(tabVC, pinEdges = false)
|
}
|
||||||
|
val ninePatch = stack.addArrangedSubview(NinePatchView(NinePatchTexture.PANEL_BG)).apply {
|
||||||
|
intrinsicContentSize = Size(75.0, 100.0)
|
||||||
|
}
|
||||||
|
val red = stack.addArrangedSubview(View()).apply {
|
||||||
|
intrinsicContentSize = Size(50.0, 50.0)
|
||||||
|
backgroundColor = Color.RED
|
||||||
|
}
|
||||||
|
|
||||||
|
val label = Label(LiteralText("Test"), wrappingMode = Label.WrappingMode.NO_WRAP).apply {
|
||||||
|
// textColor = Color.BLACK
|
||||||
|
}
|
||||||
|
// stack.addArrangedSubview(label)
|
||||||
|
val button = red.addSubview(Button(label))
|
||||||
|
|
||||||
|
val field = TextField("Test") {
|
||||||
|
println("new value: ${it.text}")
|
||||||
|
}
|
||||||
|
stack.addArrangedSubview(field)
|
||||||
|
|
||||||
view.solver.dsl {
|
view.solver.dsl {
|
||||||
tabVC.view.centerXAnchor equalTo view.centerXAnchor
|
stack.topAnchor equalTo 0
|
||||||
tabVC.view.centerYAnchor equalTo view.centerYAnchor
|
stack.centerXAnchor equalTo window!!.centerXAnchor
|
||||||
tabVC.view.widthAnchor equalTo 200
|
stack.widthAnchor equalTo 100
|
||||||
tabVC.view.heightAnchor equalTo 150
|
|
||||||
|
|
||||||
|
button.centerXAnchor equalTo red.centerXAnchor
|
||||||
|
button.centerYAnchor equalTo red.centerYAnchor
|
||||||
|
// label.heightAnchor equalTo 9
|
||||||
|
button.heightAnchor equalTo 20
|
||||||
|
|
||||||
|
field.widthAnchor equalTo stack.widthAnchor
|
||||||
|
field.heightAnchor equalTo 20
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addWindow(Window(viewController))
|
addWindow(Window(viewController))
|
||||||
|
|
||||||
|
// val viewController = object: ViewController() {
|
||||||
|
// override fun viewDidLoad() {
|
||||||
|
// super.viewDidLoad()
|
||||||
|
//
|
||||||
|
// val tabs = arrayOf(
|
||||||
|
// Tab(Label("A"), AViewController()),
|
||||||
|
// Tab(Label("B"), BViewController()),
|
||||||
|
// )
|
||||||
|
// val tabVC = TabViewController(tabs)
|
||||||
|
// embedChild(tabVC, pinEdges = false)
|
||||||
|
//
|
||||||
|
// view.solver.dsl {
|
||||||
|
// tabVC.view.centerXAnchor equalTo view.centerXAnchor
|
||||||
|
// tabVC.view.centerYAnchor equalTo view.centerYAnchor
|
||||||
|
// tabVC.view.widthAnchor equalTo 200
|
||||||
|
// tabVC.view.heightAnchor equalTo 150
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// addWindow(Window(viewController))
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Tab(
|
data class Tab(
|
||||||
|
|
Loading…
Reference in New Issue