[Editor] Enable opening map on double-click on project structure panel

This commit is contained in:
2021-02-11 21:00:59 +01:00
parent b496d047cd
commit 989d7e94ed
7 changed files with 76 additions and 22 deletions

View File

@@ -4,6 +4,7 @@ import com.bartlomiejpluta.base.editor.command.context.UndoableScope
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
import com.bartlomiejpluta.base.editor.map.view.wizard.MapCreationWizard
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
import com.bartlomiejpluta.base.editor.project.context.ProjectContext
import com.bartlomiejpluta.base.editor.project.model.Project
import com.bartlomiejpluta.base.editor.project.view.ProjectSettingsFragment
@@ -27,6 +28,7 @@ class MainController : Controller() {
val modal = find<ProjectSettingsFragment>().apply { openModal(block = true, resizable = false) }
if (modal.result) {
openMaps.clear()
projectContext.project = project
projectContext.save()
}
@@ -49,10 +51,24 @@ class MainController : Controller() {
}
}
fun loadProject() {
fun openProject() {
chooseFile(
title = "Load Project",
filters = arrayOf(FileChooser.ExtensionFilter("BASE Editor Project (*.bep)", "*.bep")),
).getOrNull(0)?.let { projectContext.open(it) }
).getOrNull(0)?.let {
openMaps.clear()
projectContext.open(it)
}
}
fun openMap(uid: String) {
if (openMaps.count { (_, map) -> map.uid == uid } == 0) {
val map = projectContext.loadMap(uid)
val vm = GameMapVM(map)
val scope = UndoableScope()
setInScope(vm, scope)
openMaps[scope] = map
}
}
}

View File

@@ -28,7 +28,7 @@ class MainMenuView : View() {
menu("Open") {
item("Project...") {
action {
mainController.loadProject()
mainController.openProject()
}
}
}

View File

@@ -4,6 +4,9 @@ import com.bartlomiejpluta.base.editor.main.controller.MainController
import com.bartlomiejpluta.base.editor.map.view.editor.MapFragment
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
import com.bartlomiejpluta.base.editor.project.context.ProjectContext
import javafx.beans.InvalidationListener
import javafx.beans.Observable
import javafx.collections.MapChangeListener
import javafx.scene.control.Tab
import tornadofx.*
@@ -35,6 +38,15 @@ class MainView : View("BASE Game Editor") {
setOnClosed { mainController.openMaps.remove(scope) }
}
}
// FIXME
// For some reason cleaning mainController.openMaps just takes off the tabs content keeping open themselves.
// The workaround is to detect if map is cleaned and the clean the tabs by hand.
mainController.openMaps.addListener(MapChangeListener {
if(it.map.isEmpty()) {
tabs.clear()
}
})
}
left = projectStructureView.root

View File

@@ -1,18 +1,20 @@
package com.bartlomiejpluta.base.editor.main.view
import com.bartlomiejpluta.base.editor.main.controller.MainController
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.project.context.ProjectContext
import com.bartlomiejpluta.base.editor.util.fx.BindingUtil
import javafx.beans.binding.Bindings
import javafx.beans.property.SimpleStringProperty
import javafx.collections.ObservableList
import javafx.scene.control.TreeItem
import javafx.scene.input.MouseEvent
import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.*
class ProjectStructureView : View() {
private val projectContext: ProjectContext by di()
private val mainController: MainController by di()
private val structureMaps = StructureCategory("Maps")
@@ -23,6 +25,7 @@ class ProjectStructureView : View() {
project?.let {
structureRoot.nameProperty.bind(it.nameProperty)
Bindings.bindContent(structureMaps.items, project.maps)
root.root.expandAll()
root.refresh()
}
}
@@ -52,6 +55,14 @@ class ProjectStructureView : View() {
else -> null
}
}
setOnMouseClicked { event ->
if(event.clickCount == 2) {
when(val item = selectionModel?.selectedItem?.value) {
is GameMapAsset -> mainController.openMap(item.uid)
}
}
}
}
private class StructureCategory(name: String = "", var items: ObservableList<out Any> = observableListOf()) {

View File

@@ -3,18 +3,17 @@ package com.bartlomiejpluta.base.editor.project.context
import com.bartlomiejpluta.base.editor.asset.model.Asset
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
import com.bartlomiejpluta.base.editor.map.serial.MapDeserializer
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.util.uid.UID
import javafx.beans.property.ObjectProperty
import javafx.beans.property.ReadOnlyObjectWrapper
import javafx.beans.property.SimpleObjectProperty
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import tornadofx.getValue
import tornadofx.select
import tornadofx.setValue
import java.io.File
import java.io.FileInputStream
@@ -32,23 +31,15 @@ class DefaultProjectContext : ProjectContext {
@Autowired
private lateinit var mapSerializer: MapSerializer
@Autowired
private lateinit var mapDeserializer: MapDeserializer
override val projectProperty = SimpleObjectProperty<Project?>() as ObjectProperty<Project?>
override var project by projectProperty
private val mapsDirectoryProperty = SimpleObjectProperty<File?>()
private val mapsDirectory by mapsDirectoryProperty
init {
projectProperty.addListener { _, _, newProject ->
when(newProject) {
null -> {
mapsDirectoryProperty.value = null
}
else -> {
mapsDirectoryProperty.value = File(newProject.sourceDirectory, MAPS_DIR).apply(File::mkdirs)
}
}
newProject?.mkdirs()
}
}
@@ -77,12 +68,15 @@ class DefaultProjectContext : ProjectContext {
it.maps += asset
save()
File(mapsDirectory, asset.source).outputStream().use { fos -> mapSerializer.serialize(map, fos) }
File(it.mapsDirectory, asset.source).outputStream().use { fos -> mapSerializer.serialize(map, fos) }
}
}
}
companion object {
const val MAPS_DIR = "maps"
}
override fun loadMap(uid: String) = project?.let {
val asset = it.maps.first { map -> map.uid == uid }
?: throw IllegalStateException("The map with uid [$uid] does not exist ")
File(it.mapsDirectory, asset.source).inputStream().use { fis -> mapDeserializer.deserialize(fis) }
} ?: throw IllegalStateException("There is no open project in the context")
}

View File

@@ -13,4 +13,5 @@ interface ProjectContext {
fun open(file: File)
fun importMap(name: String, map: GameMap)
fun loadMap(uid: String): GameMap
}

View File

@@ -1,6 +1,7 @@
package com.bartlomiejpluta.base.editor.project.model
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.project.context.DefaultProjectContext
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.property.SimpleStringProperty
import tornadofx.getValue
@@ -16,4 +17,23 @@ class Project {
val sourceDirectory by sourceDirectoryProperty
val maps = observableListOf<GameMapAsset>()
val mapsDirectoryProperty = SimpleObjectProperty<File>()
var mapsDirectory by mapsDirectoryProperty
private set
init {
sourceDirectoryProperty.addListener { _, _, dir ->
dir?.let { mapsDirectory = File(it, MAPS_DIR) }
}
}
fun mkdirs() {
sourceDirectory?.mkdirs()
mapsDirectory?.mkdirs()
}
companion object {
const val MAPS_DIR = "maps"
}
}