diff --git a/extras/rhubarb-for-spine/src/main/kotlin/com/rhubarb_lip_sync/rhubarb_for_spine/AnimationFileModel.kt b/extras/rhubarb-for-spine/src/main/kotlin/com/rhubarb_lip_sync/rhubarb_for_spine/AnimationFileModel.kt index 53f496e..7b2cc63 100644 --- a/extras/rhubarb-for-spine/src/main/kotlin/com/rhubarb_lip_sync/rhubarb_for_spine/AnimationFileModel.kt +++ b/extras/rhubarb-for-spine/src/main/kotlin/com/rhubarb_lip_sync/rhubarb_for_spine/AnimationFileModel.kt @@ -27,7 +27,7 @@ class AnimationFileModel(animationFilePath: Path, private val executor: Executor mouthShapes = if (mouthSlot != null) { val mouthNames = spineJson.getSlotAttachmentNames(mouthSlot) MouthShape.values().filter { mouthNames.contains(mouthNaming.getName(it)) } - } else null + } else listOf() mouthSlotError = if (mouthSlot != null) null else "No slot with mouth drawings specified." @@ -75,6 +75,19 @@ class AnimationFileModel(animationFilePath: Path, private val executor: Executor } val busy by busyProperty + val validProperty = SimpleBooleanProperty().apply { + val errorProperties = arrayOf(mouthSlotErrorProperty, mouthShapesErrorProperty) + bind(object : BooleanBinding() { + init { + super.bind(*errorProperties) + } + override fun computeValue(): Boolean { + return errorProperties.all { it.value == null } + } + }) + } + val valid by validProperty + private fun saveAnimation(mouthCues: List, audioEventName: String) { val animationName = getAnimationName(audioEventName) spineJson.createOrUpdateAnimation(mouthCues, audioEventName, animationName, mouthSlot, mouthNaming) @@ -94,8 +107,13 @@ class AnimationFileModel(animationFilePath: Path, private val executor: Executor if (missingBasicShapes.isEmpty()) return null val result = StringBuilder() - result.append("Mouth shapes ${missingBasicShapes.joinToString()}") - result.appendln(if (missingBasicShapes.count() > 1) " are missing." else " is missing.") + val missingShapesString = missingBasicShapes.joinToString() + result.appendln( + if (missingBasicShapes.count() > 1) + "Mouth shapes $missingShapesString are missing." + else + "Mouth shape $missingShapesString is missing." + ) val first = MouthShape.basicShapes.first() val last = MouthShape.basicShapes.last() diff --git a/extras/rhubarb-for-spine/src/main/kotlin/com/rhubarb_lip_sync/rhubarb_for_spine/MainView.kt b/extras/rhubarb-for-spine/src/main/kotlin/com/rhubarb_lip_sync/rhubarb_for_spine/MainView.kt index 76a0823..b797d13 100644 --- a/extras/rhubarb-for-spine/src/main/kotlin/com/rhubarb_lip_sync/rhubarb_for_spine/MainView.kt +++ b/extras/rhubarb-for-spine/src/main/kotlin/com/rhubarb_lip_sync/rhubarb_for_spine/MainView.kt @@ -1,5 +1,8 @@ package com.rhubarb_lip_sync.rhubarb_for_spine +import javafx.beans.binding.Bindings +import javafx.beans.property.Property +import javafx.beans.property.SimpleBooleanProperty import javafx.beans.property.SimpleStringProperty import javafx.event.ActionEvent import javafx.event.EventHandler @@ -77,6 +80,7 @@ class MainView : View() { } fieldset("Audio events") { tableview { + placeholder = Label("There are no events with associated audio files.") columnResizePolicy = SmartResize.POLICY column("Event", AudioFileModel::eventNameProperty) .weigthedWidth(1.0) @@ -112,6 +116,10 @@ class MainView : View() { val audioFileModel = this@tableview.items[index] audioFileModel.performAction() } + val invalidProperty: Property = fileModelProperty + .select { it!!.validProperty } + .select { SimpleBooleanProperty(!it) } + disableProperty().bind(invalidProperty) } else null