From 353f4167163ccfe61fe3e3b65a1be3a1b061e10e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Sun, 21 Feb 2021 18:11:52 +0100 Subject: [PATCH] [Editor] Enable Assets importing and removing through Project Structure panel --- .../editor/main/view/ProjectStructureView.kt | 71 ++++++++++++++----- .../project/context/DefaultProjectContext.kt | 8 +++ .../editor/project/context/ProjectContext.kt | 3 + .../base/editor/project/model/Project.kt | 2 + 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/ProjectStructureView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/ProjectStructureView.kt index 082adf21..b3d6ae5a 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/ProjectStructureView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/ProjectStructureView.kt @@ -9,6 +9,7 @@ import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset import javafx.beans.binding.Bindings import javafx.beans.property.SimpleStringProperty import javafx.collections.ObservableList +import javafx.scene.Node import javafx.scene.control.ContextMenu import javafx.scene.control.MenuItem import javafx.scene.control.TreeCell @@ -23,9 +24,17 @@ class ProjectStructureView : View() { private val projectContext: ProjectContext by di() private val mainController: MainController by di() - private val structureMaps = StructureCategory("Maps") - private val structureTileSets = StructureCategory("Tile Sets") - private val structureImages = StructureCategory("Images") + private val structureMaps = StructureCategory("Maps").apply { + menuitem("New Map...") { mainController.createEmptyMap() } + } + + private val structureTileSets = StructureCategory("Tile Sets").apply { + menuitem("Import Tile Set...") { mainController.importTileSet() } + } + + private val structureImages = StructureCategory("Images").apply { + menuitem("Import Image...") { mainController.importImage() } + } private val structureRoot = StructureCategory( name = "Project", items = observableListOf( @@ -59,14 +68,7 @@ class ProjectStructureView : View() { } setCellFactory { - StructureItemTreeCell { item, name -> - item.apply { - if (this is Asset) { - this.name = name - projectContext.save() - } - } - } + StructureItemTreeCell(this@ProjectStructureView::renameAsset, this@ProjectStructureView::deleteAsset) } setOnMouseClicked { event -> @@ -80,14 +82,32 @@ class ProjectStructureView : View() { } } + private fun renameAsset(asset: Asset, name: String) = asset.apply { + this.name = name + projectContext.save() + } + + private fun deleteAsset(asset: Asset) { + projectContext.deleteAsset(asset) + projectContext.save() + } + private class StructureCategory(name: String = "", var items: ObservableList = observableListOf()) { val nameProperty = SimpleStringProperty(name) val name by nameProperty + val menu = ContextMenu() + + fun menuitem(text: String, graphic: Node? = null, action: () -> Unit) { + MenuItem(text, graphic).apply { + action { action() } + menu.items.add(this) + } + } } private class StructureItemConverter( private val cell: TreeCell, - private val onUpdate: (item: Any, name: String) -> Any + private val onUpdate: (item: Asset, name: String) -> Asset ) : StringConverter() { override fun toString(item: Any?): String = when (item) { is StructureCategory -> item.name @@ -100,14 +120,21 @@ class ProjectStructureView : View() { // the actual update must be done from the execute() method of the Command object // so that the Command object has access to the actual as well as the new value of layer name. // That's why we are running the submission logic in the converter. - override fun fromString(string: String?): Any = string?.let { onUpdate(cell.item, it) } ?: "" + override fun fromString(string: String?): Any = when (val item = cell.item) { + is Asset -> string?.let { onUpdate(item, it) } ?: "" + is StructureCategory -> item.name + else -> "" + } } - private class StructureItemTreeCell(onUpdate: (item: Any, name: String) -> Any) : TextFieldTreeCell() { + private class StructureItemTreeCell( + renameAsset: (asset: Asset, name: String) -> Asset, + deleteAsset: (asset: Asset) -> Unit + ) : TextFieldTreeCell() { private val assetMenu = ContextMenu() init { - converter = StructureItemConverter(this, onUpdate) + converter = StructureItemConverter(this, renameAsset) MenuItem("Rename").apply { action { treeView.isEditable = true @@ -117,6 +144,14 @@ class ProjectStructureView : View() { assetMenu.items.add(this) } + + MenuItem("Delete").apply { + action { + deleteAsset(item as Asset) + } + + assetMenu.items.add(this) + } } override fun updateItem(item: Any?, empty: Boolean) { @@ -128,8 +163,10 @@ class ProjectStructureView : View() { return } - if (!isEditing && item is Asset) { - contextMenu = assetMenu + contextMenu = when (item) { + is Asset -> if (isEditing) null else assetMenu + is StructureCategory -> item.menu + else -> null } text = when (item) { 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 cd3691ef..4234ff68 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 @@ -146,4 +146,12 @@ 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 deleteAsset(asset: Asset) { + project?.let { + it.assetLists.firstOrNull { assets -> assets.remove(asset) } + ?: throw IllegalStateException("The asset does not belong to any of the assets lists") + + asset.file.delete() + } ?: throw IllegalStateException("There is no open project in the context") + } } \ 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 6f1e715b..a213f333 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,5 +1,6 @@ package com.bartlomiejpluta.base.editor.project.context +import com.bartlomiejpluta.base.editor.asset.model.Asset 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 @@ -27,4 +28,6 @@ interface ProjectContext { fun importImage(data: ImageAssetData) fun findImageAsset(uid: String): ImageAsset fun loadImage(uid: String): Image + + fun deleteAsset(asset: Asset) } \ 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 cbf46597..7cd634d6 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 @@ -21,6 +21,8 @@ class Project { val tileSets = observableListOf() val images = observableListOf() + val assetLists = listOf(maps, tileSets, images) + val mapsDirectoryProperty = SimpleObjectProperty() var mapsDirectory by mapsDirectoryProperty private set