diff --git a/libui-ktx/src/main/kotlin/widgets.kt b/libui-ktx/src/main/kotlin/widgets.kt index c82dea55..e5ed238b 100644 --- a/libui-ktx/src/main/kotlin/widgets.kt +++ b/libui-ktx/src/main/kotlin/widgets.kt @@ -2,6 +2,7 @@ package libui.ktx import kotlinx.cinterop.* import libui.* +import libui.ktx.databinding.* import libui.ktx.draw.Color import libui.ktx.draw.Font import platform.posix.* @@ -38,8 +39,9 @@ import platform.posix.* /** DSL builder for a simple single line text entry widget. */ inline fun Container.textfield( readonly: Boolean = false, + modelEntry: ModelEntry? = null, init: TextField.() -> Unit = {} -): TextField = add(TextField() +): TextField = add(modelEntry?.let { TextField(it) } ?: TextField() .apply { if (readonly) this.readonly = readonly } .apply(init)) @@ -61,8 +63,20 @@ inline fun Container.searchfield( .apply(init)) /** Wrapper class for [uiEntry] - a simple single line text entry widget */ -open class TextField internal constructor(alloc: CPointer?) : Control(alloc) { - constructor(): this(uiNewEntry()) +open class TextField internal constructor(alloc: CPointer?, val modelEntry: ModelEntry) : Control(alloc) { + constructor(): this(ModelEntry("")) + constructor(alloc: CPointer?): this(alloc, ModelEntry("")) + constructor(modelEntry: ModelEntry): this(uiNewEntry(), modelEntry) { + this.value = modelEntry.get() + modelEntry.addListener({newValue -> this.value = newValue}) + addOnChangeListener() + } + + private fun addOnChangeListener() { + uiEntryOnChanged(ptr, staticCFunction { _, ref -> with(ref.to()) { + modelEntry.update(this.value) + }}, ref.asCPointer()) + } /** The current text of the TextField. */ var value: String @@ -386,12 +400,16 @@ class TimePicker : DateTimePicker(uiNewTimePicker()) { /** DSL builder for a static text label. */ inline fun Container.label( - text: String, + text: String = "", + modelEntry: ModelEntry? = null, init: Label.() -> Unit = {} -): Label = add(Label(text).apply(init)) +): Label = add(Label(modelEntry ?: ModelEntry(text)).apply(init)) /** Wrapper class for [uiLabel] - a static text label. */ -class Label(text: String) : Control(uiNewLabel(text)) { +class Label(modelEntry: ModelEntry) : Control(uiNewLabel(modelEntry.get())) { + init { + modelEntry.addListener({newText -> this.text = newText}) + } /** The static text of the label. */ var text: String diff --git a/samples/data-binding-1/build.gradle b/samples/data-binding-1/build.gradle new file mode 100644 index 00000000..70ba9c97 --- /dev/null +++ b/samples/data-binding-1/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'konan' + +def konanUserDir = System.getenv("KONAN_DATA_DIR") ?: "${System.getProperty("user.home")}/.konan" +def windresDir = "$konanUserDir/dependencies/msys2-mingw-w64-x86_64-gcc-7.3.0-clang-llvm-lld-6.0.1/bin" +def rcFile = file('src/main/resources/samples.rc') +def resFile = file("$buildDir/konan/resources/samples.res") +task windowsResources(type: Exec) { + inputs.file rcFile + outputs.file resFile + commandLine "$windresDir/windres", rcFile, '-O', 'coff', '-o', resFile + environment 'PATH', "$windresDir;${System.getenv('PATH')}" +} + +konanArtifacts { + program('data-binding-1') { + libraries { + artifact project(':libui-ktx'), 'libui-ktx' + } + target('mingw') { + dependsOn 'windowsResources' + inputs.file resFile + linkerOpts "$resFile -mwindows" + } + } +} diff --git a/samples/data-binding-1/src/main/kotlin/data-binding-1.kt b/samples/data-binding-1/src/main/kotlin/data-binding-1.kt new file mode 100644 index 00000000..0dde3327 --- /dev/null +++ b/samples/data-binding-1/src/main/kotlin/data-binding-1.kt @@ -0,0 +1,20 @@ +import libui.ktx.* +import libui.ktx.databinding.* + +fun main(args: Array) { + class Model { + val myString = ModelEntry("Hello kotlin-libui!") + } + val model = Model() + + appWindow( + title = "Data-binding Example #1", + width = 320, + height = 100 + ) { + vbox { + label(modelEntry = model.myString) + textfield(modelEntry = model.myString) + } + } +} diff --git a/samples/data-binding-1/src/main/resources/samples.manifest b/samples/data-binding-1/src/main/resources/samples.manifest new file mode 100644 index 00000000..372956c8 --- /dev/null +++ b/samples/data-binding-1/src/main/resources/samples.manifest @@ -0,0 +1,43 @@ + + + + Your application description here. + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/data-binding-1/src/main/resources/samples.rc b/samples/data-binding-1/src/main/resources/samples.rc new file mode 100644 index 00000000..5e8c8e9f --- /dev/null +++ b/samples/data-binding-1/src/main/resources/samples.rc @@ -0,0 +1,6 @@ +// this is a UTF-8 file +#pragma code_page(65001) + +// this is the Common Controls 6 manifest +// 1 is the value of CREATEPROCESS_MANIFEST_RESOURCE_ID and 24 is the value of RT_MANIFEST +1 24 "samples.manifest" diff --git a/settings.gradle b/settings.gradle index d4689da9..7f65c30e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,6 +4,7 @@ include ':libui' include ':libui-ktx' include ':samples:controlgallery' +include ':samples:data-binding-1' include ':samples:datetime' include ':samples:drawtext' include ':samples:form'