Fix property editor

This commit is contained in:
Alexander Nozik 2022-08-14 10:47:36 +03:00
parent 43362f51f5
commit eeec89f0e6
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
10 changed files with 55 additions and 42 deletions

View File

@ -37,4 +37,9 @@ apiValidation {
ignoredPackages.add("info.laht.threekt") ignoredPackages.add("info.laht.threekt")
} }
readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md")
//rootProject.extensions.configure<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension> {
// versions.webpackCli.version = "4.10.0"
//}

View File

@ -12,6 +12,7 @@ pluginManagement {
maven("https://repo.kotlin.link") maven("https://repo.kotlin.link")
mavenCentral() mavenCentral()
gradlePluginPortal() gradlePluginPortal()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
} }
plugins { plugins {

View File

@ -5,7 +5,7 @@ import react.RBuilder
import react.dom.client.createRoot import react.dom.client.createRoot
import react.key import react.key
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.isEmpty
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.getStyle import space.kscience.visionforge.getStyle
import space.kscience.visionforge.react.EditorPropertyState import space.kscience.visionforge.react.EditorPropertyState
@ -23,17 +23,18 @@ public fun RBuilder.visionPropertyEditor(
) { ) {
card("Properties") { card("Properties") {
child(PropertyEditor){ child(PropertyEditor) {
attrs{ attrs {
this.key = key?.toString() this.key = key?.toString()
this.meta = vision.properties.root() this.meta = vision.properties.root()
this.updates = vision.properties.changes this.updates = vision.properties.changes
this.descriptor = descriptor this.descriptor = descriptor
this.scope = vision.manager?.context ?: error("Orphan vision could not be observed") this.scope = vision.manager?.context ?: error("Orphan vision could not be observed")
this.getPropertyState = {name-> this.getPropertyState = { name ->
if(vision.properties.own?.get(name)!= null){ val ownMeta = vision.properties.own?.getMeta(name)
if (ownMeta != null && !ownMeta.isEmpty()) {
EditorPropertyState.Defined EditorPropertyState.Defined
} else if(vision.properties.root()[name] != null){ } else if (vision.properties.root().getValue(name) != null) {
// TODO differentiate // TODO differentiate
EditorPropertyState.Default() EditorPropertyState.Default()
} else { } else {

View File

@ -8,8 +8,4 @@ dependencies{
api("org.jetbrains.kotlin-wrappers:kotlin-react-dom") api("org.jetbrains.kotlin-wrappers:kotlin-react-dom")
// implementation(npm("react-select","4.3.0")) // implementation(npm("react-select","4.3.0"))
implementation(project(":visionforge-threejs")) implementation(project(":visionforge-threejs"))
}
rootProject.extensions.configure<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension> {
versions.webpackCli.version = "4.10.0"
} }

View File

@ -19,13 +19,13 @@ public val MultiSelectChooser: FC<ValueChooserProps> = fc("MultiSelectChooser")
val onChange: (Event) -> Unit = { event: Event -> val onChange: (Event) -> Unit = { event: Event ->
val newSelected = (event.target as HTMLSelectElement).selectedOptions.asList() val newSelected = (event.target as HTMLSelectElement).selectedOptions.asList()
.map { (it as HTMLOptionElement).value.asValue() } .map { (it as HTMLOptionElement).value.asValue() }
props.meta.value = newSelected.asValue() props.onValueChange(newSelected.asValue())
} }
select { select {
attrs { attrs {
multiple = true multiple = true
values = (props.meta.value?.list ?: emptyList()).mapTo(HashSet()) { it.string } values = (props.value?.list ?: emptyList()).mapTo(HashSet()) { it.string }
onChangeFunction = onChange onChangeFunction = onChange
} }
props.descriptor?.allowedValues?.forEach { optionValue -> props.descriptor?.allowedValues?.forEach { optionValue ->

View File

@ -73,8 +73,8 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
var expanded: Boolean by useState { props.expanded ?: true } var expanded: Boolean by useState { props.expanded ?: true }
val descriptor: MetaDescriptor? = useMemo(props.descriptor, props.name) { props.descriptor?.get(props.name) } val descriptor: MetaDescriptor? = useMemo(props.descriptor, props.name) { props.descriptor?.get(props.name) }
var property: MutableMeta by useState { props.meta.getOrCreate(props.name) } var property: MutableMeta by useState { props.meta.getOrCreate(props.name) }
var editorPropertyState: EditorPropertyState by useState { props.getPropertyState(props.name) }
val defined = props.getPropertyState(props.name) == EditorPropertyState.Defined
val keys = useMemo(descriptor) { val keys = useMemo(descriptor) {
buildSet { buildSet {
@ -91,6 +91,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
fun update() { fun update() {
property = props.meta.getOrCreate(props.name) property = props.meta.getOrCreate(props.name)
editorPropertyState = props.getPropertyState(props.name)
} }
useEffect(props.meta) { useEffect(props.meta) {
@ -136,7 +137,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
styledSpan { styledSpan {
css { css {
+TreeStyles.treeLabel +TreeStyles.treeLabel
if (!defined) { if (editorPropertyState != EditorPropertyState.Defined) {
+TreeStyles.treeLabelInactive +TreeStyles.treeLabelInactive
} }
} }
@ -152,8 +153,12 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
ValueChooser { ValueChooser {
attrs { attrs {
this.descriptor = descriptor this.descriptor = descriptor
this.meta = property this.state = editorPropertyState
this.state = props.getPropertyState(props.name) this.value = property.value
this.onValueChange = {
property.value = it
editorPropertyState = props.getPropertyState(props.name)
}
} }
} }
} }
@ -177,7 +182,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
} }
+"\u00D7" +"\u00D7"
attrs { attrs {
if (!defined) { if (editorPropertyState!= EditorPropertyState.Defined) {
disabled = true disabled = true
} else { } else {
onClickFunction = removeClick onClickFunction = removeClick

View File

@ -20,22 +20,24 @@ import styled.styledInput
@JsExport @JsExport
public val RangeValueChooser: FC<ValueChooserProps> = fc("RangeValueChooser") { props -> public val RangeValueChooser: FC<ValueChooserProps> = fc("RangeValueChooser") { props ->
var innerValue by useState(props.meta.double) var innerValue by useState(props.value?.double)
var rangeDisabled: Boolean by useState(props.meta.value == null) var rangeDisabled: Boolean by useState(props.state != EditorPropertyState.Defined)
val handleDisable: (Event) -> Unit = { val handleDisable: (Event) -> Unit = {
val checkBoxValue = (it.target as HTMLInputElement).checked val checkBoxValue = (it.target as HTMLInputElement).checked
rangeDisabled = !checkBoxValue rangeDisabled = !checkBoxValue
props.meta.value = if (!checkBoxValue) { props.onValueChange(
null if (!checkBoxValue) {
} else { null
innerValue?.asValue() } else {
} innerValue?.asValue()
}
)
} }
val handleChange: (Event) -> Unit = { val handleChange: (Event) -> Unit = {
val newValue = (it.target as HTMLInputElement).value val newValue = (it.target as HTMLInputElement).value
props.meta.value = newValue.toDoubleOrNull()?.asValue() props.onValueChange(newValue.toDoubleOrNull()?.asValue())
innerValue = newValue.toDoubleOrNull() innerValue = newValue.toDoubleOrNull()
} }

View File

@ -27,17 +27,18 @@ import styled.styledSelect
public external interface ValueChooserProps : Props { public external interface ValueChooserProps : Props {
public var descriptor: MetaDescriptor? public var descriptor: MetaDescriptor?
public var meta: MutableMeta
public var state: EditorPropertyState public var state: EditorPropertyState
public var value: Value?
public var onValueChange: (Value?) -> Unit
} }
@JsExport @JsExport
public val StringValueChooser: FC<ValueChooserProps> = fc("StringValueChooser") { props -> public val StringValueChooser: FC<ValueChooserProps> = fc("StringValueChooser") { props ->
var value by useState(props.meta.string ?: "") var value by useState(props.value?.string ?: "")
val keyDown: (Event) -> Unit = { event -> val keyDown: (Event) -> Unit = { event ->
if (event.type == "keydown" && event.asDynamic().key == "Enter") { if (event.type == "keydown" && event.asDynamic().key == "Enter") {
value = (event.target as HTMLInputElement).value value = (event.target as HTMLInputElement).value
props.meta.value = value.asValue() props.onValueChange(value.asValue())
} }
} }
val handleChange: (Event) -> Unit = { val handleChange: (Event) -> Unit = {
@ -59,7 +60,7 @@ public val StringValueChooser: FC<ValueChooserProps> = fc("StringValueChooser")
public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser") { props -> public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser") { props ->
val handleChange: (Event) -> Unit = { val handleChange: (Event) -> Unit = {
val newValue = (it.target as HTMLInputElement).checked val newValue = (it.target as HTMLInputElement).checked
props.meta.value = newValue.asValue() props.onValueChange(newValue.asValue())
} }
styledInput(type = InputType.checkBox) { styledInput(type = InputType.checkBox) {
css { css {
@ -67,7 +68,7 @@ public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser"
} }
attrs { attrs {
//this.attributes["indeterminate"] = (props.item == null).toString() //this.attributes["indeterminate"] = (props.item == null).toString()
checked = props.meta.boolean ?: false checked = props.value?.boolean ?: false
onChangeFunction = handleChange onChangeFunction = handleChange
} }
} }
@ -75,7 +76,7 @@ public val BooleanValueChooser: FC<ValueChooserProps> = fc("BooleanValueChooser"
@JsExport @JsExport
public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser") { props -> public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser") { props ->
var innerValue by useState(props.meta.string ?: "") var innerValue by useState(props.value?.string ?: "")
val keyDown: (Event) -> Unit = { event -> val keyDown: (Event) -> Unit = { event ->
if (event.type == "keydown" && event.asDynamic().key == "Enter") { if (event.type == "keydown" && event.asDynamic().key == "Enter") {
innerValue = (event.target as HTMLInputElement).value innerValue = (event.target as HTMLInputElement).value
@ -83,7 +84,7 @@ public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser")
if (number == null) { if (number == null) {
console.error("The input value $innerValue is not a number") console.error("The input value $innerValue is not a number")
} else { } else {
props.meta.value = number.asValue() props.onValueChange(number.asValue())
} }
} }
} }
@ -113,10 +114,10 @@ public val NumberValueChooser: FC<ValueChooserProps> = fc("NumberValueChooser")
@JsExport @JsExport
public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") { props -> public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") { props ->
var selected by useState(props.meta.string ?: "") var selected by useState(props.value?.string ?: "")
val handleChange: (Event) -> Unit = { val handleChange: (Event) -> Unit = {
selected = (it.target as HTMLSelectElement).value selected = (it.target as HTMLSelectElement).value
props.meta.value = selected.asValue() props.onValueChange(selected.asValue())
} }
styledSelect { styledSelect {
css { css {
@ -128,7 +129,7 @@ public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") {
} }
} }
attrs { attrs {
this.value = props.meta.string ?: "" this.value = props.value?.string ?: ""
multiple = false multiple = false
onChangeFunction = handleChange onChangeFunction = handleChange
} }
@ -138,7 +139,7 @@ public val ComboValueChooser: FC<ValueChooserProps> = fc("ComboValueChooser") {
@JsExport @JsExport
public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") { props -> public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") { props ->
val handleChange: (Event) -> Unit = { val handleChange: (Event) -> Unit = {
props.meta.value = (it.target as HTMLInputElement).value.asValue() props.onValueChange((it.target as HTMLInputElement).value.asValue())
} }
styledInput(type = InputType.color) { styledInput(type = InputType.color) {
css { css {
@ -146,7 +147,7 @@ public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") {
margin(0.px) margin(0.px)
} }
attrs { attrs {
this.value = props.meta.value?.let { value -> this.value = props.value?.let { value ->
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int) if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
else value.string else value.string
} ?: "#000000" } ?: "#000000"

View File

@ -183,9 +183,11 @@ public val ThreeCanvasWithControls: FC<ThreeCanvasWithControlsProps> = fc("Three
} }
} }
} }
p { vision.styles.takeIf { it.isNotEmpty() }?.let { styles ->
b { +"Styles: " } p {
+vision.styles.joinToString(separator = ", ") b { +"Styles: " }
+styles.joinToString(separator = ", ")
}
} }
} }
} }

View File

@ -26,7 +26,7 @@ public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
val canvas = document.createElement("canvas") as HTMLCanvasElement val canvas = document.createElement("canvas") as HTMLCanvasElement
val context = canvas.getContext("2d") as CanvasRenderingContext2D val context = canvas.getContext("2d") as CanvasRenderingContext2D
context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}" context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
context.fillStyle = obj.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).value ?: "black" context.fillStyle = obj.properties.getValue(SolidMaterial.MATERIAL_COLOR_KEY, false, true)?.value ?: "black"
context.textBaseline = CanvasTextBaseline.MIDDLE context.textBaseline = CanvasTextBaseline.MIDDLE
val metrics = context.measureText(obj.text) val metrics = context.measureText(obj.text)
//canvas.width = metrics.width.toInt() //canvas.width = metrics.width.toInt()