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 tornadofx.setValue
import java.util.concurrent.ExecutorService 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 spineJson = SpineJson(animationFilePath)
val slotsProperty = SimpleObjectProperty<ObservableList<String>>() val slotsProperty = SimpleObjectProperty<ObservableList<String>>()
@ -55,7 +55,11 @@ class AnimationFileModel(animationFilePath: Path, private val executor: Executor
val audioFileModelsProperty = SimpleListProperty<AudioFileModel>( val audioFileModelsProperty = SimpleListProperty<AudioFileModel>(
spineJson.audioEvents spineJson.audioEvents
.map { event -> .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() .observable()
) )
@ -88,14 +92,11 @@ class AnimationFileModel(animationFilePath: Path, private val executor: Executor
} }
val valid by validProperty val valid by validProperty
private fun saveAnimation(mouthCues: List<MouthCue>, audioEventName: String) { private fun saveAnimation(animationName: String, audioEventName: String, mouthCues: List<MouthCue>) {
val animationName = getAnimationName(audioEventName)
spineJson.createOrUpdateAnimation(mouthCues, audioEventName, animationName, mouthSlot, mouthNaming) spineJson.createOrUpdateAnimation(mouthCues, audioEventName, animationName, mouthSlot, mouthNaming)
spineJson.save() spineJson.save()
} }
private fun getAnimationName(audioEventName: String): String = "say_$audioEventName"
init { init {
slots = spineJson.slots.observable() slots = spineJson.slots.observable()
mouthSlot = spineJson.guessMouthSlot() mouthSlot = spineJson.guessMouthSlot()

View File

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

View File

@ -29,7 +29,7 @@ class MainModel(private val executor: ExecutorService) {
throw Exception("File does not exist.") throw Exception("File does not exist.")
} }
animationFileModel = AnimationFileModel(path, executor) animationFileModel = AnimationFileModel(this, path, executor)
} }
} }
var filePathString by filePathStringProperty var filePathString by filePathStringProperty
@ -42,5 +42,11 @@ class MainModel(private val executor: ExecutorService) {
var animationFileModel by animationFileModelProperty var animationFileModel by animationFileModelProperty
private set 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() private fun getDefaultPathString() = FX.application.parameters.raw.firstOrNull()
} }

View File

@ -71,6 +71,17 @@ class MainView : View() {
errorProperty().bind(fileModelProperty.select { it!!.mouthShapesErrorProperty }) 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") { fieldset("Audio events") {
tableview<AudioFileModel> { tableview<AudioFileModel> {
@ -78,6 +89,8 @@ class MainView : View() {
columnResizePolicy = SmartResize.POLICY columnResizePolicy = SmartResize.POLICY
column("Event", AudioFileModel::eventNameProperty) column("Event", AudioFileModel::eventNameProperty)
.weigthedWidth(1.0) .weigthedWidth(1.0)
column("Animation name", AudioFileModel::animationNameProperty)
.weigthedWidth(1.0)
column("Audio file", AudioFileModel::displayFilePathProperty) column("Audio file", AudioFileModel::displayFilePathProperty)
.weigthedWidth(1.0) .weigthedWidth(1.0)
column("Dialog", AudioFileModel::dialogProperty).apply { column("Dialog", AudioFileModel::dialogProperty).apply {

View File

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