[Editor] Add support for in-memory executable scripts

This commit is contained in:
2021-03-24 21:03:20 +01:00
parent 9fd8e84fea
commit 0b5ea55b87
8 changed files with 92 additions and 11 deletions

View File

@@ -6,7 +6,13 @@ import tornadofx.getValue
import tornadofx.setValue import tornadofx.setValue
import tornadofx.toProperty import tornadofx.toProperty
class Code(fileNode: FileNode, val typeProperty: Property<CodeType>, code: String) { class Code(
fileNode: FileNode,
val typeProperty: Property<CodeType>,
code: String,
saveable: Boolean = true,
execute: ((String) -> Unit)? = null
) {
val fileNodeProperty = fileNode.toProperty() val fileNodeProperty = fileNode.toProperty()
val fileNode by fileNodeProperty val fileNode by fileNodeProperty
@@ -14,4 +20,13 @@ class Code(fileNode: FileNode, val typeProperty: Property<CodeType>, code: Strin
val codeProperty = code.toProperty() val codeProperty = code.toProperty()
var code by codeProperty var code by codeProperty
val saveableProperty = saveable.toProperty()
val saveable by saveableProperty
val executeProperty = execute.toProperty()
fun execute() {
executeProperty.value?.let { it(code) }
}
} }

View File

@@ -7,6 +7,7 @@ import com.bartlomiejpluta.base.editor.code.model.CodeScope
import com.bartlomiejpluta.base.editor.code.model.CodeType import com.bartlomiejpluta.base.editor.code.model.CodeType
import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
import com.bartlomiejpluta.base.editor.file.model.InMemoryStringFileNode
import com.bartlomiejpluta.base.editor.file.model.ScriptAssetFileNode import com.bartlomiejpluta.base.editor.file.model.ScriptAssetFileNode
import com.bartlomiejpluta.base.editor.project.context.ProjectContext import com.bartlomiejpluta.base.editor.project.context.ProjectContext
import javafx.beans.binding.Bindings import javafx.beans.binding.Bindings
@@ -31,7 +32,7 @@ class CodeEditorView : View() {
}, codeVM.typeProperty) }, codeVM.typeProperty)
private val editable = Bindings.createBooleanBinding( private val editable = Bindings.createBooleanBinding(
{ codeVM.fileNode is FileSystemNode || codeVM.fileNode is ScriptAssetFileNode }, { codeVM.fileNode is FileSystemNode || codeVM.fileNode is ScriptAssetFileNode || codeVM.fileNode is InMemoryStringFileNode },
codeVM.itemProperty codeVM.itemProperty
) )
@@ -50,9 +51,12 @@ class CodeEditorView : View() {
override val root = borderpane { override val root = borderpane {
top = toolbar { top = toolbar {
button(graphic = FontIcon("fa-floppy-o")) {
enableWhen(codeVM.dirty.and(editable)) if (codeVM.saveable && editable.value) {
action { save() } button(graphic = FontIcon("fa-floppy-o")) {
enableWhen(codeVM.dirty)
action { save() }
}
} }
button(graphic = FontIcon("fa-undo")) { button(graphic = FontIcon("fa-undo")) {
@@ -64,6 +68,12 @@ class CodeEditorView : View() {
enableWhen(editable) enableWhen(editable)
action { redo() } action { redo() }
} }
if (codeVM.executeProperty.isNotNull.value) {
button(graphic = FontIcon("fa-play")) {
action { execute() }
}
}
} }
center = editor center = editor
@@ -73,8 +83,13 @@ class CodeEditorView : View() {
fun undo() = editor.undo() fun undo() = editor.undo()
fun save() = codeVM.item?.let { fun save() = codeVM.takeIf { editable.value && it.saveable }?.item?.let {
codeVM.commit(codeVM.codeProperty) codeVM.commit(codeVM.codeProperty)
projectContext.saveScript(it) projectContext.saveScript(it)
} }
fun execute() {
codeVM.commit(codeVM.codeProperty)
codeVM.execute()
}
} }

View File

@@ -14,4 +14,13 @@ class CodeVM(code: Code) : ItemViewModel<Code>(code) {
val codeProperty = bind(Code::codeProperty) val codeProperty = bind(Code::codeProperty)
var code by codeProperty var code by codeProperty
val saveableProperty = bind(Code::saveableProperty)
val saveable by saveableProperty
val executeProperty = bind(Code::executeProperty)
fun execute() {
item?.execute()
}
} }

View File

@@ -0,0 +1,30 @@
package com.bartlomiejpluta.base.editor.file.model
import javafx.beans.property.SimpleLongProperty
import tornadofx.getValue
import tornadofx.toProperty
class InMemoryStringFileNode(name: String, extension: String, val content: String) : FileNode {
override val nameProperty = "$name.$extension".toProperty()
override val name by nameProperty
override val extensionProperty = extension.toProperty()
override val extension by extensionProperty
override val nameWithoutExtensionProperty = name.toProperty()
override val nameWithoutExtension by nameWithoutExtensionProperty
override val absolutePathProperty = "".toProperty()
override val absolutePath by absolutePathProperty
override val type = FileType.FILE
override val parent = null
override val children = emptyList<FileNode>()
override val lastModifiedProperty = SimpleLongProperty(0)
override val lastModified by lastModifiedProperty
override fun inputStream() = content.byteInputStream()
}

View File

@@ -98,12 +98,18 @@ class MainController : Controller() {
} }
} }
fun openScript(fsNode: FileNode, line: Int = 1, column: Int = 1) { fun openScript(
fsNode: FileNode,
line: Int = 1,
column: Int = 1,
execute: ((String) -> Unit)? = null,
saveable: Boolean = true
) {
val findScript = { script: Code -> script.fileNode.absolutePath == fsNode.absolutePath } val findScript = { script: Code -> script.fileNode.absolutePath == fsNode.absolutePath }
val updateExistingScope = { scope: CodeScope -> scope.setCaretPosition(line, column) } val updateExistingScope = { scope: CodeScope -> scope.setCaretPosition(line, column) }
openItem(findScript, updateExistingScope) { openItem(findScript, updateExistingScope) {
val code = projectContext.loadScript(fsNode) val code = projectContext.loadScript(fsNode, execute, saveable)
val vm = CodeVM(code) val vm = CodeVM(code)
val scope = CodeScope(line, column) val scope = CodeScope(line, column)
setInScope(vm, scope) setInScope(vm, scope)

View File

@@ -6,6 +6,7 @@ import com.bartlomiejpluta.base.editor.code.view.build.BuildLogsView
import com.bartlomiejpluta.base.editor.code.view.editor.CodeEditorFragment import com.bartlomiejpluta.base.editor.code.view.editor.CodeEditorFragment
import com.bartlomiejpluta.base.editor.code.view.list.ScriptFilesView import com.bartlomiejpluta.base.editor.code.view.list.ScriptFilesView
import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM
import com.bartlomiejpluta.base.editor.database.view.list.TablesListView
import com.bartlomiejpluta.base.editor.event.AppendBuildLogsEvent import com.bartlomiejpluta.base.editor.event.AppendBuildLogsEvent
import com.bartlomiejpluta.base.editor.event.AppendProcessLogsEvent import com.bartlomiejpluta.base.editor.event.AppendProcessLogsEvent
import com.bartlomiejpluta.base.editor.event.SelectMainViewTabEvent import com.bartlomiejpluta.base.editor.event.SelectMainViewTabEvent
@@ -36,6 +37,7 @@ class MainView : View("BASE Game Editor") {
private val buildLogsView = find<BuildLogsView>() private val buildLogsView = find<BuildLogsView>()
private val processLogsView = find<ProcessLogsView>() private val processLogsView = find<ProcessLogsView>()
private val projectPropertiesView = find<ProjectParametersView>() private val projectPropertiesView = find<ProjectParametersView>()
private val databaseTablesListView = find<TablesListView>()
private val openTabs = mutableMapOf<Scope, Tab>() private val openTabs = mutableMapOf<Scope, Tab>()
@@ -123,6 +125,10 @@ class MainView : View("BASE Game Editor") {
this += assetsView this += assetsView
} }
item("Database", expanded = false) {
this += databaseTablesListView
}
item("Project Parameters") { item("Project Parameters") {
enableWhen(projectContext.projectProperty.isNotNull) enableWhen(projectContext.projectProperty.isNotNull)
this += projectPropertiesView this += projectPropertiesView

View File

@@ -247,7 +247,7 @@ class DefaultProjectContext : ProjectContext {
} ?: throw IllegalStateException("There is no open project in the context") } ?: throw IllegalStateException("There is no open project in the context")
} }
override fun loadScript(fileNode: FileNode): Code { override fun loadScript(fileNode: FileNode, execute: ((String) -> Unit)?, saveable: Boolean): Code {
val typeProperty = SimpleObjectProperty<CodeType>().apply { val typeProperty = SimpleObjectProperty<CodeType>().apply {
bind(createObjectBinding({ bind(createObjectBinding({
when (fileNode.extension.toLowerCase()) { when (fileNode.extension.toLowerCase()) {
@@ -261,7 +261,7 @@ class DefaultProjectContext : ProjectContext {
val code = fileNode.readText() val code = fileNode.readText()
return Code(fileNode, typeProperty, code) return Code(fileNode, typeProperty, code, saveable, execute)
} }
override fun saveScript(code: Code) { override fun saveScript(code: Code) {

View File

@@ -49,6 +49,6 @@ interface ProjectContext {
fun importSound(data: SoundAssetData) fun importSound(data: SoundAssetData)
fun deleteAsset(asset: Asset) fun deleteAsset(asset: Asset)
fun loadScript(fileNode: FileNode): Code fun loadScript(fileNode: FileNode, execute: ((String) -> Unit)?, saveable: Boolean): Code
fun saveScript(code: Code) fun saveScript(code: Code)
} }