From 9589618ca2c8b45a69d67378f813051cb8829ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Fri, 12 Feb 2021 08:35:06 +0100 Subject: [PATCH] [Editor] Enable importing TileSets to project --- .../editor/main/controller/MainController.kt | 16 +++ .../base/editor/main/view/MainMenuView.kt | 10 ++ .../editor/map/view/editor/MapFragment.kt | 2 +- .../project/context/DefaultProjectContext.kt | 15 +++ .../editor/project/context/ProjectContext.kt | 3 + .../serial/ProtobufProjectSerializer.kt | 2 + .../tileset/asset/TileSetAssetBuilder.kt | 21 +++ .../tileset/view/{ => editor}/TileSetView.kt | 4 +- .../view/importing/ImportTileSetFragment.kt | 127 ++++++++++++++++++ .../viewmodel/TileSetAssetBuilderVM.kt | 20 +++ 10 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/asset/TileSetAssetBuilder.kt rename editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/{ => editor}/TileSetView.kt (89%) create mode 100644 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/importing/ImportTileSetFragment.kt create mode 100644 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/viewmodel/TileSetAssetBuilderVM.kt 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 0e3e4abc..433926ea 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 @@ -9,6 +9,8 @@ import com.bartlomiejpluta.base.editor.project.context.ProjectContext import com.bartlomiejpluta.base.editor.project.model.Project 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.TileSetAssetBuilderVM import javafx.stage.FileChooser import org.springframework.stereotype.Component import tornadofx.* @@ -71,4 +73,18 @@ class MainController : Controller() { openMaps[scope] = map } } + + fun importTileSet() { + val vm = TileSetAssetBuilderVM() + val scope = Scope() + setInScope(vm, scope) + + find(scope).apply { + onComplete { + projectContext.importTileSet(it) + } + + openModal(block = true) + } + } } \ No newline at end of file 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 ee87d029..80c7f7f5 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 @@ -34,6 +34,16 @@ class MainMenuView : View() { } } + menu("Project") { + item("Import Tile Set...") { + enableWhen(projectContext.projectProperty.isNotNull) + + action { + mainController.importTileSet() + } + } + } + menu("Edit") { item("Undo") item("Redo") diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapFragment.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapFragment.kt index b49e4f7f..9ebe07c4 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapFragment.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapFragment.kt @@ -1,7 +1,7 @@ package com.bartlomiejpluta.base.editor.map.view.editor import com.bartlomiejpluta.base.editor.command.context.UndoableScope -import com.bartlomiejpluta.base.editor.tileset.view.TileSetView +import com.bartlomiejpluta.base.editor.tileset.view.editor.TileSetView import tornadofx.* 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 fcb0fd28..96a1163a 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 @@ -8,6 +8,8 @@ import com.bartlomiejpluta.base.editor.map.serial.MapSerializer import com.bartlomiejpluta.base.editor.project.model.Project import com.bartlomiejpluta.base.editor.project.serial.ProjectDeserializer import com.bartlomiejpluta.base.editor.project.serial.ProjectSerializer +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAssetBuilder import com.bartlomiejpluta.base.editor.util.uid.UID import javafx.beans.property.ObjectProperty import javafx.beans.property.SimpleObjectProperty @@ -79,4 +81,17 @@ class DefaultProjectContext : ProjectContext { File(it.mapsDirectory, asset.source).inputStream().use { fis -> mapDeserializer.deserialize(fis) } } ?: throw IllegalStateException("There is no open project in the context") + + override fun importTileSet(builder: TileSetAssetBuilder) { + project?.let { + UID.next(it.tileSets.map(Asset::uid)).let { uid -> + val source = "$uid.${builder.file.extension}" + val targetFile = File(it.tileSetsDirectory, source) + builder.file.copyTo(targetFile) + it.tileSets += TileSetAsset(uid, source, builder.name, builder.rows, builder.columns) + + save() + } + } + } } \ No newline at end of file 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 b54e879e..cfad4e5a 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 @@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.project.context import com.bartlomiejpluta.base.editor.map.model.map.GameMap import com.bartlomiejpluta.base.editor.project.model.Project +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAssetBuilder import javafx.beans.property.ObjectProperty import java.io.File @@ -14,4 +15,6 @@ interface ProjectContext { fun importMap(name: String, map: GameMap) fun loadMap(uid: String): GameMap + + fun importTileSet(builder: TileSetAssetBuilder) } \ 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 bf94a27c..47df3412 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 @@ -28,5 +28,7 @@ class ProtobufProjectSerializer : ProjectSerializer { .setUid(tileSet.uid) .setSource(tileSet.source) .setName(tileSet.name) + .setRows(tileSet.rows) + .setColumns(tileSet.columns) .build() } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/asset/TileSetAssetBuilder.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/asset/TileSetAssetBuilder.kt new file mode 100644 index 00000000..1307e33b --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/asset/TileSetAssetBuilder.kt @@ -0,0 +1,21 @@ +package com.bartlomiejpluta.base.editor.tileset.asset + +import javafx.beans.property.SimpleIntegerProperty +import javafx.beans.property.SimpleObjectProperty +import javafx.beans.property.SimpleStringProperty +import java.io.File +import tornadofx.* + +class TileSetAssetBuilder { + val nameProperty = SimpleStringProperty() + var name by nameProperty + + val rowsProperty = SimpleIntegerProperty(1) + var rows by rowsProperty + + val columnsProperty = SimpleIntegerProperty(1) + var columns by columnsProperty + + val fileProperty = SimpleObjectProperty() + var file by fileProperty +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/TileSetView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/editor/TileSetView.kt similarity index 89% rename from editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/TileSetView.kt rename to editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/editor/TileSetView.kt index f6ce9548..6bd357a5 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/TileSetView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/editor/TileSetView.kt @@ -1,8 +1,8 @@ -package com.bartlomiejpluta.base.editor.tileset.view +package com.bartlomiejpluta.base.editor.tileset.view.editor -import com.bartlomiejpluta.base.editor.tileset.component.TileSetPane import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM +import com.bartlomiejpluta.base.editor.tileset.component.TileSetPane import tornadofx.View import tornadofx.plusAssign import tornadofx.scrollpane 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 new file mode 100644 index 00000000..c2c3449b --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/importing/ImportTileSetFragment.kt @@ -0,0 +1,127 @@ +package com.bartlomiejpluta.base.editor.tileset.view.importing + +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAssetBuilder +import com.bartlomiejpluta.base.editor.tileset.viewmodel.TileSetAssetBuilderVM +import javafx.beans.property.SimpleObjectProperty +import javafx.scene.Cursor +import javafx.scene.image.Image +import javafx.stage.FileChooser +import tornadofx.* + +class ImportTileSetFragment : Fragment("Import Tile Set") { + private val builderVM = find() + private val imagePreview = SimpleObjectProperty() + + private var onCompleteConsumer: ((TileSetAssetBuilder) -> Unit)? = null + + init { + builderVM.fileProperty.addListener { _, _, file -> + when(file) { + null -> imagePreview.value = null + else -> file.inputStream().use { imagePreview.value = Image(it) } + } + } + } + + fun onComplete(consumer: (TileSetAssetBuilder) -> Unit) { + this.onCompleteConsumer = consumer + } + + override val root = form { + prefHeight = 480.0 + + fieldset("Import Tile Set") { + hbox { + vbox { + scrollpane { + prefWidth = 300.0 + prefHeightProperty().bind(this@form.heightProperty()) + imageview(imagePreview) + tooltip = tooltip("Click to choose sprite file") + cursor = Cursor.HAND + + setOnMouseClicked { + builderVM.file = chooseFile( + title = "Select Sprite", + filters = arrayOf(FileChooser.ExtensionFilter("PNG Images (*.png)", "*.png")) + ).getOrNull(0) + } + + builderVM.validationContext.addValidator(this@vbox, builderVM.fileProperty) { + when { + it == null -> error("This field is required") + !it.exists() -> error("The file must exist") + else -> null + } + } + } + } + + vbox { + paddingLeft = 20.0 + + field("Tile Set Name") { + textfield(builderVM.nameProperty) { + required() + trimWhitespace() + } + } + + field("Tile Set Rows") { + textfield(builderVM.rowsProperty) { + stripNonInteger() + required() + trimWhitespace() + + validator { + val value = it?.toIntOrNull() + when { + value == null -> error("This field is required") + value < 1 -> error("The value must not be lower than 1") + else -> null + } + } + } + } + + field("Tile Set Columns") { + textfield(builderVM.columnsProperty) { + stripNonInteger() + required() + trimWhitespace() + + validator { + val value = it?.toIntOrNull() + when { + value == null -> error("This field is required") + value < 1 -> error("The value must not be lower than 1") + else -> null + } + } + } + } + } + } + } + + buttonbar { + button("Import") { + action { + if(builderVM.commit()) { + onCompleteConsumer?.let { it(builderVM.item) } + close() + } + } + } + + button("Reset") { + action { builderVM.rollback() } + } + + + button("Cancel") { + action { close() } + } + } + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/viewmodel/TileSetAssetBuilderVM.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/viewmodel/TileSetAssetBuilderVM.kt new file mode 100644 index 00000000..cbe87b25 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/viewmodel/TileSetAssetBuilderVM.kt @@ -0,0 +1,20 @@ +package com.bartlomiejpluta.base.editor.tileset.viewmodel + +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAssetBuilder +import tornadofx.ItemViewModel +import tornadofx.getValue +import tornadofx.setValue + +class TileSetAssetBuilderVM : ItemViewModel(TileSetAssetBuilder()) { + val nameProperty = bind(TileSetAssetBuilder::nameProperty) + var name by nameProperty + + val rowsProperty = bind(TileSetAssetBuilder::rowsProperty) + var rows by rowsProperty + + val columnsProperty = bind(TileSetAssetBuilder::columnsProperty) + var columns by columnsProperty + + val fileProperty = bind(TileSetAssetBuilder::fileProperty) + var file by fileProperty +} \ No newline at end of file