Allowing the animation naming to be customized

This commit is contained in:
Daniel Wolf 2018-02-09 22:18:48 +01:00
parent ce54ba60a7
commit 5db03da56f
5 changed files with 63 additions and 16 deletions

View File

@ -12,7 +12,7 @@ import tornadofx.observable
import tornadofx.setValue
import java.util.concurrent.ExecutorService
class AnimationFileModel(animationFilePath: Path, private val executor: ExecutorService) {
class AnimationFileModel(val parentModel: MainModel, animationFilePath: Path, private val executor: ExecutorService) {
val spineJson = SpineJson(animationFilePath)
val slotsProperty = SimpleObjectProperty<ObservableList<String>>()
@ -55,7 +55,11 @@ class AnimationFileModel(animationFilePath: Path, private val executor: Executor
val audioFileModelsProperty = SimpleListProperty<AudioFileModel>(
spineJson.audioEvents
.map { event ->
AudioFileModel(event, this, executor, { result -> saveAnimation(result, event.name) })
var audioFileModel: AudioFileModel? = null
val reportResult: (List<MouthCue>) -> Unit =
{ result -> saveAnimation(audioFileModel!!.animationName, event.name, result) }
audioFileModel = AudioFileModel(event, this, executor, reportResult)
return@map audioFileModel
}
.observable()
)
@ -88,14 +92,11 @@ class AnimationFileModel(animationFilePath: Path, private val executor: Executor
}
val valid by validProperty
private fun saveAnimation(mouthCues: List<MouthCue>, audioEventName: String) {
val animationName = getAnimationName(audioEventName)
private fun saveAnimation(animationName: String, audioEventName: String, mouthCues: List<MouthCue>) {
spineJson.createOrUpdateAnimation(mouthCues, audioEventName, animationName, mouthSlot, mouthNaming)
spineJson.save()
}
private fun getAnimationName(audioEventName: String): String = "say_$audioEventName"
init {
slots = spineJson.slots.observable()
mouthSlot = spineJson.guessMouthSlot()

View File

@ -29,6 +29,23 @@ class AudioFileModel(
val displayFilePathProperty = SimpleStringProperty(audioEvent.relativeAudioFilePath)
val displayFilePath by displayFilePathProperty
val animationNameProperty = SimpleStringProperty().apply {
val mainModel = parentModel.parentModel
bind(object : ObjectBinding<String>() {
init {
super.bind(
mainModel.animationPrefixProperty,
eventNameProperty,
mainModel.animationSuffixProperty
)
}
override fun computeValue(): String {
return mainModel.animationPrefix + eventName + mainModel.animationSuffix
}
})
}
val animationName by animationNameProperty
val dialogProperty = SimpleStringProperty(audioEvent.dialog)
val dialog: String? by dialogProperty
@ -36,8 +53,17 @@ class AudioFileModel(
var animationProgress by animationProgressProperty
private set
private val animatedPreviouslyProperty = SimpleBooleanProperty(false) // TODO: Initial value
private var animatedPreviously by animatedPreviouslyProperty
private val animatedProperty = SimpleBooleanProperty().apply {
bind(object : ObjectBinding<Boolean>() {
init {
super.bind(animationNameProperty, parentModel.spineJson.animationNames)
}
override fun computeValue(): Boolean {
return parentModel.spineJson.animationNames.contains(animationName)
}
})
}
private var animated by animatedProperty
private val futureProperty = SimpleObjectProperty<Future<*>?>()
private var future by futureProperty
@ -45,7 +71,7 @@ class AudioFileModel(
private val audioFileStateProperty = SimpleObjectProperty<AudioFileState>().apply {
bind(object : ObjectBinding<AudioFileState>() {
init {
super.bind(animatedPreviouslyProperty, futureProperty, animationProgressProperty)
super.bind(animatedProperty, futureProperty, animationProgressProperty)
}
override fun computeValue(): AudioFileState {
return if (future != null) {
@ -57,7 +83,7 @@ class AudioFileModel(
else
AudioFileState(AudioFileStatus.Pending)
} else {
if (animatedPreviously)
if (animated)
AudioFileState(AudioFileStatus.Done)
else
AudioFileState(AudioFileStatus.NotAnimated)
@ -133,7 +159,6 @@ class AudioFileModel(
val result = rhubarbTask.call()
runAndWait {
reportResult(result)
animatedPreviously = true
}
} finally {
runAndWait {

View File

@ -29,7 +29,7 @@ class MainModel(private val executor: ExecutorService) {
throw Exception("File does not exist.")
}
animationFileModel = AnimationFileModel(path, executor)
animationFileModel = AnimationFileModel(this, path, executor)
}
}
var filePathString by filePathStringProperty
@ -42,5 +42,11 @@ class MainModel(private val executor: ExecutorService) {
var animationFileModel by animationFileModelProperty
private set
val animationPrefixProperty = SimpleStringProperty("say_")
var animationPrefix by animationPrefixProperty
val animationSuffixProperty = SimpleStringProperty("")
var animationSuffix by animationSuffixProperty
private fun getDefaultPathString() = FX.application.parameters.raw.firstOrNull()
}

View File

@ -71,6 +71,17 @@ class MainView : View() {
errorProperty().bind(fileModelProperty.select { it!!.mouthShapesErrorProperty })
}
}
field("Animation naming") {
textfield {
maxWidth = 100.0
textProperty().bindBidirectional(mainModel.animationPrefixProperty)
}
label("<audio event name>")
textfield {
maxWidth = 100.0
textProperty().bindBidirectional(mainModel.animationSuffixProperty)
}
}
}
fieldset("Audio events") {
tableview<AudioFileModel> {
@ -78,6 +89,8 @@ class MainView : View() {
columnResizePolicy = SmartResize.POLICY
column("Event", AudioFileModel::eventNameProperty)
.weigthedWidth(1.0)
column("Animation name", AudioFileModel::animationNameProperty)
.weigthedWidth(1.0)
column("Audio file", AudioFileModel::displayFilePathProperty)
.weigthedWidth(1.0)
column("Dialog", AudioFileModel::dialogProperty).apply {

View File

@ -1,6 +1,7 @@
package com.rhubarb_lip_sync.rhubarb_for_spine
import com.beust.klaxon.*
import javafx.collections.FXCollections.observableSet
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Path
@ -94,10 +95,9 @@ class SpineJson(val filePath: Path) {
return attachments.map { it.key }
}
fun hasAnimation(animationName: String): Boolean {
val animations = json.obj("animations") ?: return false
return animations.any { it.key == animationName }
}
val animationNames = observableSet<String>(
json.obj("animations")?.map{ it.key }?.toSet() ?: setOf()
)
fun createOrUpdateAnimation(mouthCues: List<MouthCue>, eventName: String, animationName: String,
mouthSlot: String, mouthNaming: MouthNaming
@ -138,6 +138,8 @@ class SpineJson(val filePath: Path) {
}
)
}
animationNames.add(animationName)
}
fun save() {