[Editor] Enable creating Widgets in Editor

The Editor does not yet support XML syntax highlighting (the Java highlighter is used as temporary replacement), also the tab name of widget asset shows the actual file name (composed of UID) instead of the asset name provided by user.
This commit is contained in:
2021-03-15 18:02:56 +01:00
parent fef7b88a51
commit c8a8cd99c6
14 changed files with 115 additions and 11 deletions

View File

@@ -4,6 +4,7 @@ import com.bartlomiejpluta.base.editor.asset.model.Asset
import com.bartlomiejpluta.base.editor.asset.model.AssetCategory
import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset
@@ -72,6 +73,7 @@ class AssetTreeCell(renameAsset: (asset: Asset, name: String) -> Asset, deleteAs
is ImageAsset -> FontIcon("fa-image")
is EntitySet -> FontIcon("fa-male")
is FontAsset -> FontIcon("fa-font")
is WidgetAsset -> FontIcon("fa-tachometer")
else -> null
}
}

View File

@@ -1,8 +1,11 @@
package com.bartlomiejpluta.base.editor.asset.model
import com.bartlomiejpluta.base.editor.file.model.FileNode
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
import javafx.beans.binding.Bindings.createObjectBinding
import javafx.beans.property.ObjectProperty
import javafx.beans.property.SimpleStringProperty
import javafx.beans.value.ObservableValue
import tornadofx.getValue
import tornadofx.setValue
import java.io.File
@@ -14,5 +17,8 @@ abstract class Asset(directory: ObjectProperty<File>, val uid: String, val sourc
val fileProperty = createObjectBinding({ File(directory.value, source) }, directory)
val file by fileProperty
val fileNodeProperty: ObservableValue<FileNode> = createObjectBinding({ FileSystemNode(file) }, fileProperty)
val fileNode by fileNodeProperty
override fun toString() = "${this.javaClass.simpleName}[name=$name, uid=$uid]"
}

View File

@@ -3,6 +3,7 @@ package com.bartlomiejpluta.base.editor.asset.view.list
import com.bartlomiejpluta.base.editor.asset.component.AssetTreeCell
import com.bartlomiejpluta.base.editor.asset.model.Asset
import com.bartlomiejpluta.base.editor.asset.model.AssetCategory
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
import com.bartlomiejpluta.base.editor.main.controller.MainController
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.project.context.ProjectContext
@@ -35,13 +36,18 @@ class AssetsListView : View() {
menuitem("Import Font...") { mainController.importFont() }
}
private val widgets = AssetCategory("Widgets").apply {
menuitem("New Widget...") { mainController.createEmptyWidget() }
}
private val rootItem = AssetCategory(
name = "Project", items = observableListOf(
maps,
tileSets,
images,
entitySet,
fonts
fonts,
widgets
)
)
@@ -54,6 +60,7 @@ class AssetsListView : View() {
Bindings.bindContent(images.items, it.images)
Bindings.bindContent(entitySet.items, it.entitySets)
Bindings.bindContent(fonts.items, it.fonts)
Bindings.bindContent(widgets.items, it.widgets)
root.root.expandAll()
}
}
@@ -79,6 +86,7 @@ class AssetsListView : View() {
if (event.clickCount == 2) {
when (val item = selectionModel?.selectedItem?.value) {
is GameMapAsset -> mainController.openMap(item.uid)
is WidgetAsset -> mainController.openScript(item.fileNode)
}
}

View File

@@ -1,5 +1,6 @@
package com.bartlomiejpluta.base.editor.code.model
enum class CodeType {
JAVA
JAVA,
XML
}

View File

@@ -23,6 +23,7 @@ class CodeEditorView : View() {
private val highlighter = Bindings.createObjectBinding({
when (codeVM.type!!) {
CodeType.JAVA -> javaSyntaxHighlighter
CodeType.XML -> javaSyntaxHighlighter
}
}, codeVM.typeProperty)
@@ -38,6 +39,7 @@ class CodeEditorView : View() {
fun shutdown() {
editor.shutdownHighlighterThread()
codeVM.fileNode
}
override val root = borderpane {

View File

@@ -0,0 +1,7 @@
package com.bartlomiejpluta.base.editor.gui.widget.asset
import com.bartlomiejpluta.base.editor.asset.model.Asset
import com.bartlomiejpluta.base.editor.project.model.Project
class WidgetAsset(project: Project, uid: String, name: String) :
Asset(project.widgetsDirectoryProperty, uid, "$uid.xml", name)

View File

@@ -0,0 +1,10 @@
package com.bartlomiejpluta.base.editor.gui.widget.asset
import tornadofx.getValue
import tornadofx.setValue
import tornadofx.toProperty
class WidgetAssetData(name: String) {
val nameProperty = name.toProperty()
var name by nameProperty
}

View File

@@ -11,6 +11,8 @@ import com.bartlomiejpluta.base.editor.event.SelectMainViewTabEvent
import com.bartlomiejpluta.base.editor.file.model.FileNode
import com.bartlomiejpluta.base.editor.gui.font.view.importing.ImportFontFragment
import com.bartlomiejpluta.base.editor.gui.font.viewmodel.FontAssetDataVM
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAssetData
import com.bartlomiejpluta.base.editor.image.view.importing.ImportImageFragment
import com.bartlomiejpluta.base.editor.image.viewmodel.ImageAssetDataVM
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
@@ -24,6 +26,7 @@ import com.bartlomiejpluta.base.editor.project.view.ProjectSettingsFragment
import com.bartlomiejpluta.base.editor.project.viewmodel.ProjectVM
import com.bartlomiejpluta.base.editor.tileset.view.importing.ImportTileSetFragment
import com.bartlomiejpluta.base.editor.tileset.viewmodel.TileSetAssetDataVM
import javafx.scene.control.TextInputDialog
import javafx.stage.FileChooser
import org.springframework.stereotype.Component
import tornadofx.*
@@ -183,6 +186,29 @@ class MainController : Controller() {
}
}
fun createEmptyWidget() {
TextInputDialog().apply {
width = 300.0
contentText = "Widget name"
title = "New Widget"
}
.showAndWait()
.map(::WidgetAssetData)
.map(projectContext::createWidget)
.map(WidgetAsset::fileNode)
.ifPresent(this::openScript)
}
fun closeAsset(asset: Asset) {
when (asset) {
is GameMapAsset -> openItems.entries.firstOrNull { (_, item) -> item is GameMap && item.uid == asset.uid }?.key?.let {
openItems.remove(it)
}
is WidgetAsset -> closeScript(asset.fileNode)
}
}
fun closeScript(fsNode: FileNode) {
openItems.entries.firstOrNull { (_, item) -> item is Code && item.fileNode.absolutePath == fsNode.absolutePath }?.key?.let {
openItems.remove(it)
@@ -195,14 +221,6 @@ class MainController : Controller() {
}
}
fun closeAsset(asset: Asset) {
when (asset) {
is GameMapAsset -> openItems.entries.firstOrNull { (_, item) -> item is GameMap && item.uid == asset.uid }?.key?.let {
openItems.remove(it)
}
}
}
fun clearResources() {
openItems.clear()
}

View File

@@ -9,6 +9,8 @@ import com.bartlomiejpluta.base.editor.entityset.asset.EntitySetAssetData
import com.bartlomiejpluta.base.editor.file.model.FileNode
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAssetData
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAssetData
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
import com.bartlomiejpluta.base.editor.image.asset.ImageAssetData
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
@@ -192,6 +194,19 @@ class DefaultProjectContext : ProjectContext {
}
}
override fun createWidget(data: WidgetAssetData) = project?.let {
UID.next(it.widgets.map(Asset::uid)).let { uid ->
val asset = WidgetAsset(it, uid, data.name)
val file = File(it.widgetsDirectory, asset.source)
file.createNewFile()
it.widgets += asset
save()
asset
}
} ?: throw IllegalStateException("There is no open project in the context")
override fun deleteAsset(asset: Asset) {
project?.let {
it.assetLists.firstOrNull { assets -> assets.remove(asset) }
@@ -206,6 +221,7 @@ class DefaultProjectContext : ProjectContext {
bind(createObjectBinding({
when (fileNode.extension.toLowerCase()) {
"java" -> CodeType.JAVA
"xml" -> CodeType.XML
else -> throw IllegalStateException("Unsupported script type")
}
}))

View File

@@ -5,6 +5,8 @@ import com.bartlomiejpluta.base.editor.code.model.Code
import com.bartlomiejpluta.base.editor.entityset.asset.EntitySetAssetData
import com.bartlomiejpluta.base.editor.file.model.FileNode
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAssetData
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAssetData
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
import com.bartlomiejpluta.base.editor.image.asset.ImageAssetData
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
@@ -38,6 +40,8 @@ interface ProjectContext {
fun importFont(data: FontAssetData)
fun createWidget(data: WidgetAssetData): WidgetAsset
fun deleteAsset(asset: Asset)
fun loadScript(fileNode: FileNode): Code
fun saveScript(code: Code)

View File

@@ -3,6 +3,7 @@ package com.bartlomiejpluta.base.editor.project.model
import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset
@@ -32,8 +33,9 @@ class Project {
val images = observableListOf<ImageAsset>()
val entitySets = observableListOf<EntitySet>()
val fonts = observableListOf<FontAsset>()
val widgets = observableListOf<WidgetAsset>()
val assetLists = listOf(maps, tileSets, images, entitySets, fonts)
val assetLists = listOf(maps, tileSets, images, entitySets, fonts, widgets)
val mapsDirectoryProperty = SimpleObjectProperty<File>()
var mapsDirectory by mapsDirectoryProperty
@@ -55,6 +57,10 @@ class Project {
var fontsDirectory by fontsDirectoryProperty
private set
val widgetsDirectoryProperty = SimpleObjectProperty<File>()
var widgetsDirectory by widgetsDirectoryProperty
private set
val codeDirectoryProperty = SimpleObjectProperty<File>()
var codeDirectory by codeDirectoryProperty
private set
@@ -90,6 +96,7 @@ class Project {
imagesDirectory = File(it, IMAGES_DIR)
entitySetsDirectory = File(it, ENTITY_SETS_DIR)
fontsDirectory = File(it, FONTS_DIR)
widgetsDirectory = File(it, WIDGETS_DIR)
codeDirectory = File(it, CODE_DIR)
buildDirectory = File(it, BUILD_DIR)
buildClassesDirectory = File(it, BUILD_CLASSES_DIR)
@@ -106,6 +113,7 @@ class Project {
imagesDirectory?.mkdirs()
entitySetsDirectory?.mkdirs()
fontsDirectory?.mkdirs()
widgetsDirectory?.mkdirs()
codeDirectory?.mkdirs()
}
@@ -118,6 +126,7 @@ class Project {
const val IMAGES_DIR = "images"
const val ENTITY_SETS_DIR = "entsets"
const val FONTS_DIR = "fonts"
const val WIDGETS_DIR = "widgets"
const val CODE_DIR = "code"
const val BUILD_DIR = "build"
const val BUILD_CLASSES_DIR = "$BUILD_DIR/classes"

View File

@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.project.serial
import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.project.model.Project
@@ -23,6 +24,7 @@ class ProtobufProjectDeserializer : ProjectDeserializer {
project.images.addAll(proto.imagesList.map { deserializeImage(project, it) })
project.entitySets.addAll(proto.entitySetsList.map { deserializeEntitySet(project, it) })
project.fonts.addAll(proto.fontsList.map { deserializeFont(project, it) })
project.widgets.addAll(proto.widgetsList.map { deserializeWidget(project, it) })
return project
}
@@ -64,4 +66,10 @@ class ProtobufProjectDeserializer : ProjectDeserializer {
source = fontAsset.source,
name = fontAsset.name
)
private fun deserializeWidget(project: Project, widget: ProjectProto.WidgetAsset) = WidgetAsset(
project = project,
uid = widget.uid,
name = widget.name
)
}

View File

@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.project.serial
import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.project.model.Project
@@ -22,6 +23,7 @@ class ProtobufProjectSerializer : ProjectSerializer {
proto.addAllImages(item.images.map(this::serializeImage))
proto.addAllEntitySets(item.entitySets.map(this::serializeEntitySet))
proto.addAllFonts(item.fonts.map(this::serializeFont))
proto.addAllWidgets(item.widgets.map(this::serializeWidget))
proto.build().writeTo(output)
}
@@ -58,4 +60,9 @@ class ProtobufProjectSerializer : ProjectSerializer {
.setSource(font.source)
.setName(font.name)
.build()
private fun serializeWidget(widget: WidgetAsset) = ProjectProto.WidgetAsset.newBuilder()
.setUid(widget.uid)
.setName(widget.name)
.build()
}

View File

@@ -11,6 +11,7 @@ message Project {
repeated ImageAsset images = 5;
repeated EntitySetAsset entitySets = 6;
repeated FontAsset fonts = 7;
repeated WidgetAsset widgets = 8;
}
message GameMapAsset {
@@ -45,4 +46,9 @@ message FontAsset {
required string uid = 1;
required string source = 2;
required string name = 3;
}
message WidgetAsset {
required string uid = 1;
required string name = 3;
}