diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/AssetTreeCell.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/AssetTreeCell.kt index 25b72468..5dfaed31 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/AssetTreeCell.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/AssetTreeCell.kt @@ -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 } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/list/AssetsListView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/list/AssetsListView.kt index a28e0909..c3f2b425 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/list/AssetsListView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/list/AssetsListView.kt @@ -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() } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/asset/CharacterSetAsset.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/asset/CharacterSetAsset.kt new file mode 100644 index 00000000..24d4ef96 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/asset/CharacterSetAsset.kt @@ -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) \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/asset/CharacterSetAssetData.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/asset/CharacterSetAssetData.kt new file mode 100644 index 00000000..ffdd7b52 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/asset/CharacterSetAssetData.kt @@ -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() + var file by fileProperty + + val rowsProperty = SimpleIntegerProperty() + var rows by rowsProperty + + val columnsProperty = SimpleIntegerProperty() + var columns by columnsProperty +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/view/importing/ImportCharacterSetFragment.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/view/importing/ImportCharacterSetFragment.kt new file mode 100644 index 00000000..61ed5875 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/view/importing/ImportCharacterSetFragment.kt @@ -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() + private val imagePreview = SimpleObjectProperty() + + 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() } + } + } + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/viewmodel/CharacterSetAssetDataVM.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/viewmodel/CharacterSetAssetDataVM.kt new file mode 100644 index 00000000..82651d10 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/characterset/viewmodel/CharacterSetAssetDataVM.kt @@ -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()) { + 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 +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt index 20fc9a7b..57875ad8 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt @@ -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(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) diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainMenuView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainMenuView.kt index 580ab121..a3396be1 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainMenuView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainMenuView.kt @@ -50,6 +50,12 @@ class MainMenuView : View() { mainController.importImage() } } + + item("Character Set...") { + action { + mainController.importCharacterSet() + } + } } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt index 8118c4a2..5d059fb3 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt @@ -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) } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt index e1b5c375..121e11d4 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt @@ -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) } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt index ae621ffe..75f998a3 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt @@ -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() val tileSets = observableListOf() val images = observableListOf() + val characterSets = observableListOf() - val assetLists = listOf(maps, tileSets, images) + val assetLists = listOf(maps, tileSets, images, characterSets) val mapsDirectoryProperty = SimpleObjectProperty() var mapsDirectory by mapsDirectoryProperty @@ -43,6 +45,10 @@ class Project { var imagesDirectory by imagesDirectoryProperty private set + val characterSetsDirectoryProperty = SimpleObjectProperty() + var characterSetsDirectory by characterSetsDirectoryProperty + private set + val codeDirectoryProperty = SimpleObjectProperty() 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" diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt index 681e78bf..3d6757ec 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt @@ -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 + ) } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt index ea4612e8..ac28d5df 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt @@ -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() } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/importing/ImportTileSetFragment.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/importing/ImportTileSetFragment.kt index 4c08b34b..a514528e 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/importing/ImportTileSetFragment.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/importing/ImportTileSetFragment.kt @@ -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) } diff --git a/proto/src/main/proto/project.proto b/proto/src/main/proto/project.proto index 6adbda51..46eff426 100644 --- a/proto/src/main/proto/project.proto +++ b/proto/src/main/proto/project.proto @@ -9,6 +9,7 @@ message Project { repeated GameMapAsset maps = 3; repeated TileSetAsset tileSets = 4; repeated ImageAsset images = 5; + repeated CharacterSetAsset characterSets = 6; } message GameMapAsset { @@ -29,4 +30,12 @@ message ImageAsset { required string uid = 1; 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; } \ No newline at end of file