diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemStringConverter.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemStringConverter.kt new file mode 100644 index 00000000..f1bce895 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemStringConverter.kt @@ -0,0 +1,22 @@ +package com.bartlomiejpluta.base.editor.code.component + +import javafx.scene.control.TreeCell +import javafx.util.StringConverter +import java.io.File + +class CodeStructureItemStringConverter( + private val cell: TreeCell, + private val onUpdate: (item: File, name: String) -> File +) : StringConverter() { + override fun toString(item: File?): String = when (item) { + is File -> item.name + else -> "" + } + + // Disclaimer: + // Because of the fact that we want to support undo/redo mechanism + // 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?) = string?.let { onUpdate(cell.item, it) } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemTreeCell.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemTreeCell.kt new file mode 100644 index 00000000..5525f107 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemTreeCell.kt @@ -0,0 +1,61 @@ +package com.bartlomiejpluta.base.editor.code.component + +import javafx.scene.control.ContextMenu +import javafx.scene.control.MenuItem +import javafx.scene.control.cell.TextFieldTreeCell +import org.kordamp.ikonli.javafx.FontIcon +import tornadofx.action +import java.io.File + +class CodeStructureItemTreeCell(renameFile: (file: File, name: String) -> File, deleteFile: (file: File) -> Unit) : + TextFieldTreeCell() { + private val fileMenu = ContextMenu() + + init { + converter = CodeStructureItemStringConverter(this, renameFile) + MenuItem("Rename").apply { + action { + treeView.isEditable = true + startEdit() + treeView.isEditable = false + } + + fileMenu.items.add(this) + } + + MenuItem("Delete").apply { + action { + deleteFile(item as File) + } + + fileMenu.items.add(this) + } + } + + override fun updateItem(item: File?, empty: Boolean) { + super.updateItem(item, empty) + + if (empty || item == null) { + text = null + graphic = null + return + } + + contextMenu = if (isEditing) null else fileMenu + text = item.name + graphic = FontIcon(getFileIcon(item)) + } + + companion object { + private fun getFileIcon(file: File): String { + if (file.isDirectory) { + return "fa-folder" + } + + return when (file.extension.toLowerCase()) { + "java" -> "fa-code" + else -> "fa-file" + } + } + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/CodeStructureView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/CodeStructureView.kt new file mode 100644 index 00000000..c512a6a2 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/CodeStructureView.kt @@ -0,0 +1,50 @@ +package com.bartlomiejpluta.base.editor.code.view + +import com.bartlomiejpluta.base.editor.code.component.CodeStructureItemTreeCell +import com.bartlomiejpluta.base.editor.main.controller.MainController +import com.bartlomiejpluta.base.editor.project.context.ProjectContext +import javafx.scene.control.TreeItem +import javafx.scene.control.TreeView +import tornadofx.* +import java.io.File + +class CodeStructureView : View() { + private val projectContext: ProjectContext by di() + private val mainController: MainController by di() + + init { + projectContext.projectProperty.addListener { _, _, project -> + project?.let { + treeView.root = TreeItem(it.codeDirectory) + treeView.populate { item -> item.value?.listFiles()?.toList() } + root.root.expandAll() + } + } + } + + private val treeView: TreeView = treeview { + setCellFactory { + CodeStructureItemTreeCell(this@CodeStructureView::renameFile, this@CodeStructureView::deleteFile) + } + + setOnMouseClicked { event -> + if (event.clickCount == 2) { + selectionModel?.selectedItem?.value + .takeIf { it?.isFile ?: false } + ?.let { mainController.openScript(it) } + } + + event.consume() + } + } + + override val root = treeView + + private fun renameFile(file: File, name: String) = file.apply { + // TODO + } + + private fun deleteFile(file: File) { + // TODO + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/component/StructureItemTreeCell.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/component/StructureItemTreeCell.kt index 551f690b..491cce33 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/component/StructureItemTreeCell.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/component/StructureItemTreeCell.kt @@ -10,7 +10,6 @@ import javafx.scene.control.MenuItem import javafx.scene.control.cell.TextFieldTreeCell import org.kordamp.ikonli.javafx.FontIcon import tornadofx.action -import java.io.File class StructureItemTreeCell(renameAsset: (asset: Asset, name: String) -> Asset, deleteAsset: (asset: Asset) -> Unit) : TextFieldTreeCell() { @@ -55,7 +54,6 @@ class StructureItemTreeCell(renameAsset: (asset: Asset, name: String) -> Asset, text = when (item) { is StructureCategory -> item.name is Asset -> item.name - is File -> item.name else -> null } @@ -64,21 +62,7 @@ class StructureItemTreeCell(renameAsset: (asset: Asset, name: String) -> Asset, is GameMapAsset -> FontIcon("fa-map") is TileSetAsset -> FontIcon("fa-th") is ImageAsset -> FontIcon("fa-image") - is File -> FontIcon(getFileIcon(item)) else -> null } } - - companion object { - private fun getFileIcon(file: File): String { - if (file.isDirectory) { - return "fa-folder" - } - - return when (file.extension.toLowerCase()) { - "java" -> "fa-code" - else -> "fa-file" - } - } - } } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainView.kt index 33f1162c..bd2fb1e2 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainView.kt @@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.main.view import com.bartlomiejpluta.base.editor.code.model.Code import com.bartlomiejpluta.base.editor.code.view.CodeEditorFragment +import com.bartlomiejpluta.base.editor.code.view.CodeStructureView import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM import com.bartlomiejpluta.base.editor.main.controller.MainController import com.bartlomiejpluta.base.editor.map.model.map.GameMap @@ -20,6 +21,7 @@ class MainView : View("BASE Game Editor") { private val mainMenuView = find() private val projectStructureView = find() + private val codeStructure = find() init { projectContext.projectProperty.addListener { _, _, project -> @@ -68,6 +70,10 @@ class MainView : View("BASE Game Editor") { } left = drawer(multiselect = true) { + item("Code Structure", expanded = true) { + this += codeStructure + } + item("Project Structure", expanded = true) { this += projectStructureView } 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 dad620a6..4b62651e 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 @@ -10,7 +10,6 @@ import javafx.beans.binding.Bindings import javafx.scene.control.TreeItem import javafx.scene.control.TreeView import tornadofx.* -import java.io.File class ProjectStructureView : View() { @@ -29,16 +28,11 @@ class ProjectStructureView : View() { menuitem("Import Image...") { mainController.importImage() } } - private val structureCode = StructureCategory("Code").apply { - menuitem("Refresh") { this@ProjectStructureView.treeView.refresh() } - } - private val structureRoot = StructureCategory( name = "Project", items = observableListOf( structureMaps, structureTileSets, - structureImages, - structureCode + structureImages ) ) @@ -49,12 +43,7 @@ class ProjectStructureView : View() { Bindings.bindContent(structureMaps.items, it.maps) Bindings.bindContent(structureTileSets.items, it.tileSets) Bindings.bindContent(structureImages.items, it.images) - - structureCode.items.clear() - structureCode.items.add(it.codeDirectory) - root.root.expandAll() - root.refresh() } } } @@ -62,10 +51,11 @@ class ProjectStructureView : View() { private val treeView: TreeView = treeview { root = TreeItem(structureRoot) + isShowRoot = false + populate { when (val value = it.value) { is StructureCategory -> value.items - is File -> value.listFiles()?.toList() ?: observableListOf() else -> null } } @@ -78,7 +68,6 @@ class ProjectStructureView : View() { if (event.clickCount == 2) { when (val item = selectionModel?.selectedItem?.value) { is GameMapAsset -> mainController.openMap(item.uid) - is File -> item.takeIf { it.isFile }?.let { mainController.openScript(item) } } }