[Editor] Enable Assets importing and removing through Project Structure panel

This commit is contained in:
2021-02-21 18:11:52 +01:00
parent 80cff63501
commit 353f416716
4 changed files with 67 additions and 17 deletions

View File

@@ -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<out Any> = 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<Any>,
private val onUpdate: (item: Any, name: String) -> Any
private val onUpdate: (item: Asset, name: String) -> Asset
) : StringConverter<Any>() {
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<Any>() {
private class StructureItemTreeCell(
renameAsset: (asset: Asset, name: String) -> Asset,
deleteAsset: (asset: Asset) -> Unit
) : TextFieldTreeCell<Any>() {
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) {

View File

@@ -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")
}
}

View File

@@ -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)
}

View File

@@ -21,6 +21,8 @@ class Project {
val tileSets = observableListOf<TileSetAsset>()
val images = observableListOf<ImageAsset>()
val assetLists = listOf(maps, tileSets, images)
val mapsDirectoryProperty = SimpleObjectProperty<File>()
var mapsDirectory by mapsDirectoryProperty
private set