[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.model.map.GameMap
import com.bartlomiejpluta.base.editor.map.view.wizard.MapCreationWizard import com.bartlomiejpluta.base.editor.map.view.wizard.MapCreationWizard
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM 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.context.ProjectContext
import com.bartlomiejpluta.base.editor.project.model.Project import com.bartlomiejpluta.base.editor.project.model.Project
import com.bartlomiejpluta.base.editor.project.view.ProjectSettingsFragment 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) } val modal = find<ProjectSettingsFragment>().apply { openModal(block = true, resizable = false) }
if (modal.result) { if (modal.result) {
openMaps.clear()
projectContext.project = project projectContext.project = project
projectContext.save() projectContext.save()
} }
@@ -49,10 +51,24 @@ class MainController : Controller() {
} }
} }
fun loadProject() { fun openProject() {
chooseFile( chooseFile(
title = "Load Project", title = "Load Project",
filters = arrayOf(FileChooser.ExtensionFilter("BASE Editor Project (*.bep)", "*.bep")), 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") { menu("Open") {
item("Project...") { item("Project...") {
action { 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.view.editor.MapFragment
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
import com.bartlomiejpluta.base.editor.project.context.ProjectContext 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 javafx.scene.control.Tab
import tornadofx.* import tornadofx.*
@@ -35,6 +38,15 @@ class MainView : View("BASE Game Editor") {
setOnClosed { mainController.openMaps.remove(scope) } 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 left = projectStructureView.root

View File

@@ -1,18 +1,20 @@
package com.bartlomiejpluta.base.editor.main.view 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.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.project.context.ProjectContext import com.bartlomiejpluta.base.editor.project.context.ProjectContext
import com.bartlomiejpluta.base.editor.util.fx.BindingUtil
import javafx.beans.binding.Bindings import javafx.beans.binding.Bindings
import javafx.beans.property.SimpleStringProperty import javafx.beans.property.SimpleStringProperty
import javafx.collections.ObservableList import javafx.collections.ObservableList
import javafx.scene.control.TreeItem import javafx.scene.control.TreeItem
import javafx.scene.input.MouseEvent
import org.kordamp.ikonli.javafx.FontIcon import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.* import tornadofx.*
class ProjectStructureView : View() { class ProjectStructureView : View() {
private val projectContext: ProjectContext by di() private val projectContext: ProjectContext by di()
private val mainController: MainController by di()
private val structureMaps = StructureCategory("Maps") private val structureMaps = StructureCategory("Maps")
@@ -23,6 +25,7 @@ class ProjectStructureView : View() {
project?.let { project?.let {
structureRoot.nameProperty.bind(it.nameProperty) structureRoot.nameProperty.bind(it.nameProperty)
Bindings.bindContent(structureMaps.items, project.maps) Bindings.bindContent(structureMaps.items, project.maps)
root.root.expandAll()
root.refresh() root.refresh()
} }
} }
@@ -52,6 +55,14 @@ class ProjectStructureView : View() {
else -> null 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()) { 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.asset.model.Asset
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
import com.bartlomiejpluta.base.editor.map.model.map.GameMap 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.map.serial.MapSerializer
import com.bartlomiejpluta.base.editor.project.model.Project import com.bartlomiejpluta.base.editor.project.model.Project
import com.bartlomiejpluta.base.editor.project.serial.ProjectDeserializer import com.bartlomiejpluta.base.editor.project.serial.ProjectDeserializer
import com.bartlomiejpluta.base.editor.project.serial.ProjectSerializer import com.bartlomiejpluta.base.editor.project.serial.ProjectSerializer
import com.bartlomiejpluta.base.editor.util.uid.UID import com.bartlomiejpluta.base.editor.util.uid.UID
import javafx.beans.property.ObjectProperty import javafx.beans.property.ObjectProperty
import javafx.beans.property.ReadOnlyObjectWrapper
import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleObjectProperty
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import tornadofx.getValue import tornadofx.getValue
import tornadofx.select
import tornadofx.setValue import tornadofx.setValue
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
@@ -32,23 +31,15 @@ class DefaultProjectContext : ProjectContext {
@Autowired @Autowired
private lateinit var mapSerializer: MapSerializer private lateinit var mapSerializer: MapSerializer
@Autowired
private lateinit var mapDeserializer: MapDeserializer
override val projectProperty = SimpleObjectProperty<Project?>() as ObjectProperty<Project?> override val projectProperty = SimpleObjectProperty<Project?>() as ObjectProperty<Project?>
override var project by projectProperty override var project by projectProperty
private val mapsDirectoryProperty = SimpleObjectProperty<File?>()
private val mapsDirectory by mapsDirectoryProperty
init { init {
projectProperty.addListener { _, _, newProject -> projectProperty.addListener { _, _, newProject ->
when(newProject) { newProject?.mkdirs()
null -> {
mapsDirectoryProperty.value = null
}
else -> {
mapsDirectoryProperty.value = File(newProject.sourceDirectory, MAPS_DIR).apply(File::mkdirs)
}
}
} }
} }
@@ -77,12 +68,15 @@ class DefaultProjectContext : ProjectContext {
it.maps += asset it.maps += asset
save() 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 { override fun loadMap(uid: String) = project?.let {
const val MAPS_DIR = "maps" 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 open(file: File)
fun importMap(name: String, map: GameMap) fun importMap(name: String, map: GameMap)
fun loadMap(uid: String): GameMap
} }

View File

@@ -1,6 +1,7 @@
package com.bartlomiejpluta.base.editor.project.model package com.bartlomiejpluta.base.editor.project.model
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset 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.SimpleObjectProperty
import javafx.beans.property.SimpleStringProperty import javafx.beans.property.SimpleStringProperty
import tornadofx.getValue import tornadofx.getValue
@@ -16,4 +17,23 @@ class Project {
val sourceDirectory by sourceDirectoryProperty val sourceDirectory by sourceDirectoryProperty
val maps = observableListOf<GameMapAsset>() 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"
}
} }