[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.asset.model.AssetCategory
import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet import com.bartlomiejpluta.base.editor.entityset.asset.EntitySet
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset 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.image.asset.ImageAsset
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset 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 ImageAsset -> FontIcon("fa-image")
is EntitySet -> FontIcon("fa-male") is EntitySet -> FontIcon("fa-male")
is FontAsset -> FontIcon("fa-font") is FontAsset -> FontIcon("fa-font")
is WidgetAsset -> FontIcon("fa-tachometer")
else -> null else -> null
} }
} }

View File

@@ -1,8 +1,11 @@
package com.bartlomiejpluta.base.editor.asset.model 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.binding.Bindings.createObjectBinding
import javafx.beans.property.ObjectProperty import javafx.beans.property.ObjectProperty
import javafx.beans.property.SimpleStringProperty import javafx.beans.property.SimpleStringProperty
import javafx.beans.value.ObservableValue
import tornadofx.getValue import tornadofx.getValue
import tornadofx.setValue import tornadofx.setValue
import java.io.File 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 fileProperty = createObjectBinding({ File(directory.value, source) }, directory)
val file by fileProperty 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]" 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.component.AssetTreeCell
import com.bartlomiejpluta.base.editor.asset.model.Asset import com.bartlomiejpluta.base.editor.asset.model.Asset
import com.bartlomiejpluta.base.editor.asset.model.AssetCategory 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.main.controller.MainController
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.project.context.ProjectContext import com.bartlomiejpluta.base.editor.project.context.ProjectContext
@@ -35,13 +36,18 @@ class AssetsListView : View() {
menuitem("Import Font...") { mainController.importFont() } menuitem("Import Font...") { mainController.importFont() }
} }
private val widgets = AssetCategory("Widgets").apply {
menuitem("New Widget...") { mainController.createEmptyWidget() }
}
private val rootItem = AssetCategory( private val rootItem = AssetCategory(
name = "Project", items = observableListOf( name = "Project", items = observableListOf(
maps, maps,
tileSets, tileSets,
images, images,
entitySet, entitySet,
fonts fonts,
widgets
) )
) )
@@ -54,6 +60,7 @@ class AssetsListView : View() {
Bindings.bindContent(images.items, it.images) Bindings.bindContent(images.items, it.images)
Bindings.bindContent(entitySet.items, it.entitySets) Bindings.bindContent(entitySet.items, it.entitySets)
Bindings.bindContent(fonts.items, it.fonts) Bindings.bindContent(fonts.items, it.fonts)
Bindings.bindContent(widgets.items, it.widgets)
root.root.expandAll() root.root.expandAll()
} }
} }
@@ -79,6 +86,7 @@ class AssetsListView : View() {
if (event.clickCount == 2) { if (event.clickCount == 2) {
when (val item = selectionModel?.selectedItem?.value) { when (val item = selectionModel?.selectedItem?.value) {
is GameMapAsset -> mainController.openMap(item.uid) 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 package com.bartlomiejpluta.base.editor.code.model
enum class CodeType { enum class CodeType {
JAVA JAVA,
XML
} }

View File

@@ -23,6 +23,7 @@ class CodeEditorView : View() {
private val highlighter = Bindings.createObjectBinding({ private val highlighter = Bindings.createObjectBinding({
when (codeVM.type!!) { when (codeVM.type!!) {
CodeType.JAVA -> javaSyntaxHighlighter CodeType.JAVA -> javaSyntaxHighlighter
CodeType.XML -> javaSyntaxHighlighter
} }
}, codeVM.typeProperty) }, codeVM.typeProperty)
@@ -38,6 +39,7 @@ class CodeEditorView : View() {
fun shutdown() { fun shutdown() {
editor.shutdownHighlighterThread() editor.shutdownHighlighterThread()
codeVM.fileNode
} }
override val root = borderpane { 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.file.model.FileNode
import com.bartlomiejpluta.base.editor.gui.font.view.importing.ImportFontFragment 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.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.view.importing.ImportImageFragment
import com.bartlomiejpluta.base.editor.image.viewmodel.ImageAssetDataVM import com.bartlomiejpluta.base.editor.image.viewmodel.ImageAssetDataVM
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset 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.project.viewmodel.ProjectVM
import com.bartlomiejpluta.base.editor.tileset.view.importing.ImportTileSetFragment import com.bartlomiejpluta.base.editor.tileset.view.importing.ImportTileSetFragment
import com.bartlomiejpluta.base.editor.tileset.viewmodel.TileSetAssetDataVM import com.bartlomiejpluta.base.editor.tileset.viewmodel.TileSetAssetDataVM
import javafx.scene.control.TextInputDialog
import javafx.stage.FileChooser import javafx.stage.FileChooser
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import tornadofx.* 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) { fun closeScript(fsNode: FileNode) {
openItems.entries.firstOrNull { (_, item) -> item is Code && item.fileNode.absolutePath == fsNode.absolutePath }?.key?.let { openItems.entries.firstOrNull { (_, item) -> item is Code && item.fileNode.absolutePath == fsNode.absolutePath }?.key?.let {
openItems.remove(it) 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() { fun clearResources() {
openItems.clear() 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.file.model.FileNode
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAssetData 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.ImageAsset
import com.bartlomiejpluta.base.editor.image.asset.ImageAssetData import com.bartlomiejpluta.base.editor.image.asset.ImageAssetData
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset 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) { override fun deleteAsset(asset: Asset) {
project?.let { project?.let {
it.assetLists.firstOrNull { assets -> assets.remove(asset) } it.assetLists.firstOrNull { assets -> assets.remove(asset) }
@@ -206,6 +221,7 @@ class DefaultProjectContext : ProjectContext {
bind(createObjectBinding({ bind(createObjectBinding({
when (fileNode.extension.toLowerCase()) { when (fileNode.extension.toLowerCase()) {
"java" -> CodeType.JAVA "java" -> CodeType.JAVA
"xml" -> CodeType.XML
else -> throw IllegalStateException("Unsupported script type") 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.entityset.asset.EntitySetAssetData
import com.bartlomiejpluta.base.editor.file.model.FileNode import com.bartlomiejpluta.base.editor.file.model.FileNode
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAssetData 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.ImageAsset
import com.bartlomiejpluta.base.editor.image.asset.ImageAssetData import com.bartlomiejpluta.base.editor.image.asset.ImageAssetData
import com.bartlomiejpluta.base.editor.map.model.map.GameMap import com.bartlomiejpluta.base.editor.map.model.map.GameMap
@@ -38,6 +40,8 @@ interface ProjectContext {
fun importFont(data: FontAssetData) fun importFont(data: FontAssetData)
fun createWidget(data: WidgetAssetData): WidgetAsset
fun deleteAsset(asset: Asset) fun deleteAsset(asset: Asset)
fun loadScript(fileNode: FileNode): Code fun loadScript(fileNode: FileNode): Code
fun saveScript(code: 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.entityset.asset.EntitySet
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset 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.image.asset.ImageAsset
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset
@@ -32,8 +33,9 @@ class Project {
val images = observableListOf<ImageAsset>() val images = observableListOf<ImageAsset>()
val entitySets = observableListOf<EntitySet>() val entitySets = observableListOf<EntitySet>()
val fonts = observableListOf<FontAsset>() 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>() val mapsDirectoryProperty = SimpleObjectProperty<File>()
var mapsDirectory by mapsDirectoryProperty var mapsDirectory by mapsDirectoryProperty
@@ -55,6 +57,10 @@ class Project {
var fontsDirectory by fontsDirectoryProperty var fontsDirectory by fontsDirectoryProperty
private set private set
val widgetsDirectoryProperty = SimpleObjectProperty<File>()
var widgetsDirectory by widgetsDirectoryProperty
private set
val codeDirectoryProperty = SimpleObjectProperty<File>() val codeDirectoryProperty = SimpleObjectProperty<File>()
var codeDirectory by codeDirectoryProperty var codeDirectory by codeDirectoryProperty
private set private set
@@ -90,6 +96,7 @@ class Project {
imagesDirectory = File(it, IMAGES_DIR) imagesDirectory = File(it, IMAGES_DIR)
entitySetsDirectory = File(it, ENTITY_SETS_DIR) entitySetsDirectory = File(it, ENTITY_SETS_DIR)
fontsDirectory = File(it, FONTS_DIR) fontsDirectory = File(it, FONTS_DIR)
widgetsDirectory = File(it, WIDGETS_DIR)
codeDirectory = File(it, CODE_DIR) codeDirectory = File(it, CODE_DIR)
buildDirectory = File(it, BUILD_DIR) buildDirectory = File(it, BUILD_DIR)
buildClassesDirectory = File(it, BUILD_CLASSES_DIR) buildClassesDirectory = File(it, BUILD_CLASSES_DIR)
@@ -106,6 +113,7 @@ class Project {
imagesDirectory?.mkdirs() imagesDirectory?.mkdirs()
entitySetsDirectory?.mkdirs() entitySetsDirectory?.mkdirs()
fontsDirectory?.mkdirs() fontsDirectory?.mkdirs()
widgetsDirectory?.mkdirs()
codeDirectory?.mkdirs() codeDirectory?.mkdirs()
} }
@@ -118,6 +126,7 @@ class Project {
const val IMAGES_DIR = "images" const val IMAGES_DIR = "images"
const val ENTITY_SETS_DIR = "entsets" const val ENTITY_SETS_DIR = "entsets"
const val FONTS_DIR = "fonts" const val FONTS_DIR = "fonts"
const val WIDGETS_DIR = "widgets"
const val CODE_DIR = "code" const val CODE_DIR = "code"
const val BUILD_DIR = "build" const val BUILD_DIR = "build"
const val BUILD_CLASSES_DIR = "$BUILD_DIR/classes" 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.entityset.asset.EntitySet
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset 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.image.asset.ImageAsset
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.project.model.Project 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.images.addAll(proto.imagesList.map { deserializeImage(project, it) })
project.entitySets.addAll(proto.entitySetsList.map { deserializeEntitySet(project, it) }) project.entitySets.addAll(proto.entitySetsList.map { deserializeEntitySet(project, it) })
project.fonts.addAll(proto.fontsList.map { deserializeFont(project, it) }) project.fonts.addAll(proto.fontsList.map { deserializeFont(project, it) })
project.widgets.addAll(proto.widgetsList.map { deserializeWidget(project, it) })
return project return project
} }
@@ -64,4 +66,10 @@ class ProtobufProjectDeserializer : ProjectDeserializer {
source = fontAsset.source, source = fontAsset.source,
name = fontAsset.name 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.entityset.asset.EntitySet
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset 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.image.asset.ImageAsset
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.project.model.Project import com.bartlomiejpluta.base.editor.project.model.Project
@@ -22,6 +23,7 @@ class ProtobufProjectSerializer : ProjectSerializer {
proto.addAllImages(item.images.map(this::serializeImage)) proto.addAllImages(item.images.map(this::serializeImage))
proto.addAllEntitySets(item.entitySets.map(this::serializeEntitySet)) proto.addAllEntitySets(item.entitySets.map(this::serializeEntitySet))
proto.addAllFonts(item.fonts.map(this::serializeFont)) proto.addAllFonts(item.fonts.map(this::serializeFont))
proto.addAllWidgets(item.widgets.map(this::serializeWidget))
proto.build().writeTo(output) proto.build().writeTo(output)
} }
@@ -58,4 +60,9 @@ class ProtobufProjectSerializer : ProjectSerializer {
.setSource(font.source) .setSource(font.source)
.setName(font.name) .setName(font.name)
.build() .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 ImageAsset images = 5;
repeated EntitySetAsset entitySets = 6; repeated EntitySetAsset entitySets = 6;
repeated FontAsset fonts = 7; repeated FontAsset fonts = 7;
repeated WidgetAsset widgets = 8;
} }
message GameMapAsset { message GameMapAsset {
@@ -46,3 +47,8 @@ message FontAsset {
required string source = 2; required string source = 2;
required string name = 3; required string name = 3;
} }
message WidgetAsset {
required string uid = 1;
required string name = 3;
}