[Editor] Add support for Character Sets
This commit is contained in:
@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.asset.component
|
||||
|
||||
import com.bartlomiejpluta.base.editor.asset.model.Asset
|
||||
import com.bartlomiejpluta.base.editor.asset.model.AssetCategory
|
||||
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
|
||||
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
|
||||
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
|
||||
import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset
|
||||
@@ -62,6 +63,7 @@ class AssetTreeCell(renameAsset: (asset: Asset, name: String) -> Asset, deleteAs
|
||||
is GameMapAsset -> FontIcon("fa-map")
|
||||
is TileSetAsset -> FontIcon("fa-th")
|
||||
is ImageAsset -> FontIcon("fa-image")
|
||||
is CharacterSetAsset -> FontIcon("fa-male")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,16 @@ class AssetsListView : View() {
|
||||
menuitem("Import Image...") { mainController.importImage() }
|
||||
}
|
||||
|
||||
private val characterSets = AssetCategory("Character Sets").apply {
|
||||
menuitem("Import Character Set...") { mainController.importCharacterSet() }
|
||||
}
|
||||
|
||||
private val rootItem = AssetCategory(
|
||||
name = "Project", items = observableListOf(
|
||||
maps,
|
||||
tileSets,
|
||||
images
|
||||
images,
|
||||
characterSets
|
||||
)
|
||||
)
|
||||
|
||||
@@ -42,6 +47,7 @@ class AssetsListView : View() {
|
||||
Bindings.bindContent(maps.items, it.maps)
|
||||
Bindings.bindContent(tileSets.items, it.tileSets)
|
||||
Bindings.bindContent(images.items, it.images)
|
||||
Bindings.bindContent(characterSets.items, it.characterSets)
|
||||
root.root.expandAll()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.bartlomiejpluta.base.editor.characterset.asset
|
||||
|
||||
import com.bartlomiejpluta.base.editor.asset.model.Asset
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
|
||||
class CharacterSetAsset(project: Project, uid: String, source: String, name: String, val rows: Int, val columns: Int) :
|
||||
Asset(project.characterSetsDirectoryProperty, uid, source, name)
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.bartlomiejpluta.base.editor.characterset.asset
|
||||
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.getValue
|
||||
import tornadofx.setValue
|
||||
import java.io.File
|
||||
|
||||
class CharacterSetAssetData {
|
||||
val nameProperty = SimpleStringProperty()
|
||||
var name by nameProperty
|
||||
|
||||
val fileProperty = SimpleObjectProperty<File>()
|
||||
var file by fileProperty
|
||||
|
||||
val rowsProperty = SimpleIntegerProperty()
|
||||
var rows by rowsProperty
|
||||
|
||||
val columnsProperty = SimpleIntegerProperty()
|
||||
var columns by columnsProperty
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.bartlomiejpluta.base.editor.characterset.view.importing
|
||||
|
||||
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAssetData
|
||||
import com.bartlomiejpluta.base.editor.characterset.viewmodel.CharacterSetAssetDataVM
|
||||
import com.bartlomiejpluta.base.editor.util.fx.TextFieldUtil
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.scene.Cursor
|
||||
import javafx.scene.image.Image
|
||||
import javafx.stage.FileChooser
|
||||
import tornadofx.*
|
||||
|
||||
class ImportCharacterSetFragment : Fragment("Import Spite") {
|
||||
private val dataVM = find<CharacterSetAssetDataVM>()
|
||||
private val imagePreview = SimpleObjectProperty<Image?>()
|
||||
|
||||
private var onCompleteConsumer: ((CharacterSetAssetData) -> Unit)? = null
|
||||
|
||||
init {
|
||||
dataVM.fileProperty.addListener { _, _, file ->
|
||||
when (file) {
|
||||
null -> imagePreview.value = null
|
||||
else -> file.inputStream().use { imagePreview.value = Image(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onComplete(consumer: (CharacterSetAssetData) -> Unit) {
|
||||
this.onCompleteConsumer = consumer
|
||||
}
|
||||
|
||||
override val root = form {
|
||||
prefHeight = 480.0
|
||||
|
||||
fieldset("Import Character Set") {
|
||||
hbox {
|
||||
vbox {
|
||||
scrollpane {
|
||||
prefWidth = 300.0
|
||||
prefHeightProperty().bind(this@form.heightProperty())
|
||||
imageview(imagePreview)
|
||||
tooltip = tooltip("Click to choose Character Set file")
|
||||
cursor = Cursor.HAND
|
||||
|
||||
setOnMouseClicked {
|
||||
dataVM.file = chooseFile(
|
||||
title = "Select Character Set",
|
||||
filters = arrayOf(FileChooser.ExtensionFilter("PNG Images (*.png)", "*.png"))
|
||||
).getOrNull(0)
|
||||
}
|
||||
|
||||
dataVM.validationContext.addValidator(this@vbox, dataVM.fileProperty) {
|
||||
when {
|
||||
it == null -> error("This field is required")
|
||||
!it.exists() -> error("The file must exist")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vbox {
|
||||
paddingLeft = 20.0
|
||||
|
||||
field("Character Set Name") {
|
||||
textfield(dataVM.nameProperty) {
|
||||
required()
|
||||
trimWhitespace()
|
||||
}
|
||||
}
|
||||
|
||||
field("Character Set Rows") {
|
||||
spinner(min = 1, max = Integer.MAX_VALUE, property = dataVM.rowsProperty, editable = true) {
|
||||
required()
|
||||
editor.textFormatter = TextFieldUtil.integerFormatter(dataVM.rows)
|
||||
}
|
||||
}
|
||||
|
||||
field("Character Set Columns") {
|
||||
spinner(min = 1, max = Integer.MAX_VALUE, property = dataVM.columnsProperty, editable = true) {
|
||||
required()
|
||||
editor.textFormatter = TextFieldUtil.integerFormatter(dataVM.columns)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buttonbar {
|
||||
button("Import") {
|
||||
action {
|
||||
if (dataVM.commit()) {
|
||||
onCompleteConsumer?.let { it(dataVM.item) }
|
||||
close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button("Reset") {
|
||||
action { dataVM.rollback() }
|
||||
}
|
||||
|
||||
|
||||
button("Cancel") {
|
||||
action { close() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.bartlomiejpluta.base.editor.characterset.viewmodel
|
||||
|
||||
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAssetData
|
||||
import tornadofx.ItemViewModel
|
||||
import tornadofx.getValue
|
||||
import tornadofx.setValue
|
||||
|
||||
class CharacterSetAssetDataVM : ItemViewModel<CharacterSetAssetData>(CharacterSetAssetData()) {
|
||||
val nameProperty = bind(CharacterSetAssetData::nameProperty)
|
||||
var name by nameProperty
|
||||
|
||||
val fileProperty = bind(CharacterSetAssetData::fileProperty)
|
||||
var file by fileProperty
|
||||
|
||||
val rowsProperty = bind(CharacterSetAssetData::rowsProperty)
|
||||
var rows by rowsProperty
|
||||
|
||||
val columnsProperty = bind(CharacterSetAssetData::columnsProperty)
|
||||
var columns by columnsProperty
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.bartlomiejpluta.base.editor.main.controller
|
||||
|
||||
import com.bartlomiejpluta.base.editor.asset.model.Asset
|
||||
import com.bartlomiejpluta.base.editor.characterset.view.importing.ImportCharacterSetFragment
|
||||
import com.bartlomiejpluta.base.editor.characterset.viewmodel.CharacterSetAssetDataVM
|
||||
import com.bartlomiejpluta.base.editor.code.model.Code
|
||||
import com.bartlomiejpluta.base.editor.code.model.CodeScope
|
||||
import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM
|
||||
@@ -151,6 +153,20 @@ class MainController : Controller() {
|
||||
}
|
||||
}
|
||||
|
||||
fun importCharacterSet() {
|
||||
val vm = CharacterSetAssetDataVM()
|
||||
val scope = Scope()
|
||||
setInScope(vm, scope)
|
||||
|
||||
find<ImportCharacterSetFragment>(scope).apply {
|
||||
onComplete {
|
||||
projectContext.importCharacterSet(it)
|
||||
}
|
||||
|
||||
openModal(block = true, resizable = false)
|
||||
}
|
||||
}
|
||||
|
||||
fun closeScript(fsNode: FileNode) {
|
||||
openItems.entries.firstOrNull { (_, item) -> item is Code && item.fileNode.absolutePath == fsNode.absolutePath }?.key?.let {
|
||||
openItems.remove(it)
|
||||
|
||||
@@ -50,6 +50,12 @@ class MainMenuView : View() {
|
||||
mainController.importImage()
|
||||
}
|
||||
}
|
||||
|
||||
item("Character Set...") {
|
||||
action {
|
||||
mainController.importCharacterSet()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.bartlomiejpluta.base.editor.project.context
|
||||
|
||||
import com.bartlomiejpluta.base.editor.asset.model.Asset
|
||||
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
|
||||
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAssetData
|
||||
import com.bartlomiejpluta.base.editor.code.model.Code
|
||||
import com.bartlomiejpluta.base.editor.code.model.CodeType
|
||||
import com.bartlomiejpluta.base.editor.code.service.JavaClassService
|
||||
@@ -162,6 +164,19 @@ class DefaultProjectContext : ProjectContext {
|
||||
File(it.imagesDirectory, asset.source).inputStream().use { fis -> Image(fis) }
|
||||
} ?: throw IllegalStateException("There is no open project in the context")
|
||||
|
||||
override fun importCharacterSet(data: CharacterSetAssetData) {
|
||||
project?.let {
|
||||
UID.next(it.characterSets.map(Asset::uid)).let { uid ->
|
||||
val source = "$uid.${data.file.extension}"
|
||||
val targetFile = File(it.characterSetsDirectory, source)
|
||||
data.file.copyTo(targetFile)
|
||||
it.characterSets += CharacterSetAsset(it, uid, source, data.name, data.rows, data.columns)
|
||||
|
||||
save()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun deleteAsset(asset: Asset) {
|
||||
project?.let {
|
||||
it.assetLists.firstOrNull { assets -> assets.remove(asset) }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bartlomiejpluta.base.editor.project.context
|
||||
|
||||
import com.bartlomiejpluta.base.editor.asset.model.Asset
|
||||
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAssetData
|
||||
import com.bartlomiejpluta.base.editor.code.model.Code
|
||||
import com.bartlomiejpluta.base.editor.file.model.FileNode
|
||||
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
|
||||
@@ -32,8 +33,9 @@ interface ProjectContext {
|
||||
fun findImageAsset(uid: String): ImageAsset
|
||||
fun loadImage(uid: String): Image
|
||||
|
||||
fun deleteAsset(asset: Asset)
|
||||
fun importCharacterSet(data: CharacterSetAssetData)
|
||||
|
||||
fun deleteAsset(asset: Asset)
|
||||
fun loadScript(fileNode: FileNode): Code
|
||||
fun saveScript(code: Code)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bartlomiejpluta.base.editor.project.model
|
||||
|
||||
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
|
||||
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
|
||||
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
|
||||
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
|
||||
@@ -28,8 +29,9 @@ class Project {
|
||||
val maps = observableListOf<GameMapAsset>()
|
||||
val tileSets = observableListOf<TileSetAsset>()
|
||||
val images = observableListOf<ImageAsset>()
|
||||
val characterSets = observableListOf<CharacterSetAsset>()
|
||||
|
||||
val assetLists = listOf(maps, tileSets, images)
|
||||
val assetLists = listOf(maps, tileSets, images, characterSets)
|
||||
|
||||
val mapsDirectoryProperty = SimpleObjectProperty<File>()
|
||||
var mapsDirectory by mapsDirectoryProperty
|
||||
@@ -43,6 +45,10 @@ class Project {
|
||||
var imagesDirectory by imagesDirectoryProperty
|
||||
private set
|
||||
|
||||
val characterSetsDirectoryProperty = SimpleObjectProperty<File>()
|
||||
var characterSetsDirectory by characterSetsDirectoryProperty
|
||||
private set
|
||||
|
||||
val codeDirectoryProperty = SimpleObjectProperty<File>()
|
||||
var codeDirectory by codeDirectoryProperty
|
||||
private set
|
||||
@@ -70,8 +76,9 @@ class Project {
|
||||
sourceDirectoryProperty.addListener { _, _, dir ->
|
||||
dir?.let {
|
||||
mapsDirectory = File(it, MAPS_DIR)
|
||||
tileSetsDirectory = File(it, TILESETS_DIR)
|
||||
tileSetsDirectory = File(it, TILE_SETS_DIR)
|
||||
imagesDirectory = File(it, IMAGES_DIR)
|
||||
characterSetsDirectory = File(it, CHARACTER_SETS_DIR)
|
||||
codeDirectory = File(it, CODE_DIR)
|
||||
buildDirectory = File(it, BUILD_DIR)
|
||||
buildClassesDirectory = File(it, BUILD_CLASSES_DIR)
|
||||
@@ -85,6 +92,7 @@ class Project {
|
||||
mapsDirectory?.mkdirs()
|
||||
tileSetsDirectory?.mkdirs()
|
||||
imagesDirectory?.mkdirs()
|
||||
characterSetsDirectory?.mkdirs()
|
||||
codeDirectory?.mkdirs()
|
||||
}
|
||||
|
||||
@@ -93,8 +101,9 @@ class Project {
|
||||
const val PROJECT_OUTPUT_JAR_FILE = "game.jar"
|
||||
|
||||
const val MAPS_DIR = "maps"
|
||||
const val TILESETS_DIR = "tilesets"
|
||||
const val TILE_SETS_DIR = "tilesets"
|
||||
const val IMAGES_DIR = "images"
|
||||
const val CHARACTER_SETS_DIR = "charsets"
|
||||
const val CODE_DIR = "code"
|
||||
const val BUILD_DIR = "build"
|
||||
const val BUILD_CLASSES_DIR = "$BUILD_DIR/classes"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bartlomiejpluta.base.editor.project.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
|
||||
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
|
||||
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
@@ -19,6 +20,7 @@ class ProtobufProjectDeserializer : ProjectDeserializer {
|
||||
project.maps.addAll(proto.mapsList.map { deserializeMap(project, it) })
|
||||
project.tileSets.addAll(proto.tileSetsList.map { deserializeTileSet(project, it) })
|
||||
project.images.addAll(proto.imagesList.map { deserializeImage(project, it) })
|
||||
project.characterSets.addAll(proto.characterSetsList.map { deserializeCharacterSet(project, it) })
|
||||
|
||||
return project
|
||||
}
|
||||
@@ -44,4 +46,14 @@ class ProtobufProjectDeserializer : ProjectDeserializer {
|
||||
source = image.source,
|
||||
name = image.name
|
||||
)
|
||||
|
||||
private fun deserializeCharacterSet(project: Project, characterSetAsset: ProjectProto.CharacterSetAsset) =
|
||||
CharacterSetAsset(
|
||||
project = project,
|
||||
uid = characterSetAsset.uid,
|
||||
source = characterSetAsset.source,
|
||||
name = characterSetAsset.name,
|
||||
rows = characterSetAsset.rows,
|
||||
columns = characterSetAsset.columns
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bartlomiejpluta.base.editor.project.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
|
||||
import com.bartlomiejpluta.base.editor.image.asset.ImageAsset
|
||||
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
@@ -18,6 +19,7 @@ class ProtobufProjectSerializer : ProjectSerializer {
|
||||
proto.addAllMaps(item.maps.map(this::serializeMap))
|
||||
proto.addAllTileSets(item.tileSets.map(this::serializeTileSet))
|
||||
proto.addAllImages(item.images.map(this::serializeImage))
|
||||
proto.addAllCharacterSets(item.characterSets.map(this::serializeCharacterSet))
|
||||
proto.build().writeTo(output)
|
||||
}
|
||||
|
||||
@@ -40,4 +42,12 @@ class ProtobufProjectSerializer : ProjectSerializer {
|
||||
.setSource(image.source)
|
||||
.setName(image.name)
|
||||
.build()
|
||||
|
||||
private fun serializeCharacterSet(characterSet: CharacterSetAsset) = ProjectProto.CharacterSetAsset.newBuilder()
|
||||
.setUid(characterSet.uid)
|
||||
.setSource(characterSet.source)
|
||||
.setName(characterSet.name)
|
||||
.setRows(characterSet.rows)
|
||||
.setColumns(characterSet.columns)
|
||||
.build()
|
||||
}
|
||||
@@ -38,12 +38,12 @@ class ImportTileSetFragment : Fragment("Import Tile Set") {
|
||||
prefWidth = 300.0
|
||||
prefHeightProperty().bind(this@form.heightProperty())
|
||||
imageview(imagePreview)
|
||||
tooltip = tooltip("Click to choose sprite file")
|
||||
tooltip = tooltip("Click to choose Tile Set file")
|
||||
cursor = Cursor.HAND
|
||||
|
||||
setOnMouseClicked {
|
||||
dataVM.file = chooseFile(
|
||||
title = "Select Sprite",
|
||||
title = "Select Tile Set",
|
||||
filters = arrayOf(FileChooser.ExtensionFilter("PNG Images (*.png)", "*.png"))
|
||||
).getOrNull(0)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ message Project {
|
||||
repeated GameMapAsset maps = 3;
|
||||
repeated TileSetAsset tileSets = 4;
|
||||
repeated ImageAsset images = 5;
|
||||
repeated CharacterSetAsset characterSets = 6;
|
||||
}
|
||||
|
||||
message GameMapAsset {
|
||||
@@ -30,3 +31,11 @@ message ImageAsset {
|
||||
required string source = 2;
|
||||
required string name = 3;
|
||||
}
|
||||
|
||||
message CharacterSetAsset {
|
||||
required string uid = 1;
|
||||
required string source = 2;
|
||||
required string name = 3;
|
||||
required uint32 rows = 4;
|
||||
required uint32 columns = 5;
|
||||
}
|
||||
Reference in New Issue
Block a user