[Editor] Enable main view's tab selection on change | implement line selection from compilation logs on opened tabs

This commit is contained in:
2021-02-25 12:04:51 +01:00
parent 1545baab57
commit c9716d438d
5 changed files with 94 additions and 51 deletions

View File

@@ -1,17 +1,18 @@
package com.bartlomiejpluta.base.editor.code.model
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
import tornadofx.toProperty
class CodeScope(line: Int, column: Int) : UndoableScope() {
private val requestCaretPositionProperty = (line to column).toProperty()
class CodeScope(private var line: Int, private var column: Int) : UndoableScope() {
var caretDisplacementRequestListener: ((line: Int, column: Int) -> Unit)? = null
set(value) {
field = value
field?.let { it(line, column) }
}
fun setCaretPosition(line: Int, column: Int) {
requestCaretPositionProperty.value = line to column
}
this.line = line
this.column = column
fun addCaretDisplacementRequestListener(listener: (line: Int, column: Int) -> Unit) {
requestCaretPositionProperty.addListener { _, _, position -> listener(position.first, position.second) }
listener(requestCaretPositionProperty.value.first, requestCaretPositionProperty.value.second)
caretDisplacementRequestListener?.let { it(line, column) }
}
}

View File

@@ -28,7 +28,7 @@ class CodeEditorView : View() {
private val editor = CodeEditor(highlighter, codeVM.codeProperty)
init {
scope.addCaretDisplacementRequestListener { line, column ->
scope.caretDisplacementRequestListener = { line, column ->
editor.setCaretPosition(line, column)
}
}

View File

@@ -0,0 +1,7 @@
package com.bartlomiejpluta.base.editor.event
import tornadofx.EventBus
import tornadofx.FXEvent
import tornadofx.Scope
class SelectMainViewTabEvent(val targetScope: Scope) : FXEvent(EventBus.RunOn.ApplicationThread)

View File

@@ -6,6 +6,7 @@ import com.bartlomiejpluta.base.editor.code.model.CodeScope
import com.bartlomiejpluta.base.editor.code.model.FileSystemNode
import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
import com.bartlomiejpluta.base.editor.event.SelectMainViewTabEvent
import com.bartlomiejpluta.base.editor.image.view.importing.ImportImageFragment
import com.bartlomiejpluta.base.editor.image.viewmodel.ImageAssetDataVM
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
@@ -76,24 +77,49 @@ class MainController : Controller() {
}
fun openMap(uid: String) {
if (openItems.count { (_, item) -> item is GameMap && item.uid == uid } == 0) {
openItem<GameMap, UndoableScope>({ it.uid == uid }) {
val map = projectContext.loadMap(uid)
val vm = GameMapVM(map)
val scope = UndoableScope()
setInScope(vm, scope)
openItems[scope] = map
scope to map
}
}
fun openScript(fsNode: FileSystemNode, line: Int = 1, column: Int = 1) {
if (openItems.count { (_, item) -> item is Code && item.file.absolutePath == fsNode.file.absolutePath } == 0) {
val findScript = { script: Code -> script.file.absolutePath == fsNode.file.absolutePath }
val updateExistingScope = { scope: CodeScope -> scope.setCaretPosition(line, column) }
openItem(findScript, updateExistingScope) {
val code = projectContext.loadScript(fsNode.fileProperty)
val vm = CodeVM(code)
val scope = CodeScope(line, column)
setInScope(vm, scope)
openItems[scope] = code
scope to code
}
}
private inline fun <reified T, S : Scope> openItem(
findItem: (item: T) -> Boolean,
updateExistingScope: (S) -> Unit = {},
createItem: () -> Pair<Scope, T>
) {
@Suppress("UNCHECKED_CAST")
val pair = openItems.entries
.filter { (_, item) -> item is T }
.map { (scope, item) -> (scope as S) to (item as T) }
.firstOrNull { (_, item) -> findItem(item) }
if (pair == null) {
val (scope, item) = createItem()
openItems[scope] = item
fire(SelectMainViewTabEvent(scope))
} else {
val scope = pair.first
updateExistingScope(scope)
fire(SelectMainViewTabEvent(scope))
}
}

View File

@@ -6,6 +6,7 @@ import com.bartlomiejpluta.base.editor.code.view.CodeEditorFragment
import com.bartlomiejpluta.base.editor.code.view.CompilerLogsView
import com.bartlomiejpluta.base.editor.code.view.ScriptFilesView
import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM
import com.bartlomiejpluta.base.editor.event.SelectMainViewTabEvent
import com.bartlomiejpluta.base.editor.event.UpdateCompilationLogEvent
import com.bartlomiejpluta.base.editor.main.controller.MainController
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
@@ -32,21 +33,7 @@ class MainView : View("BASE Game Editor") {
private var compilationLogItem: DrawerItem by singleAssign()
init {
projectContext.projectProperty.addListener { _, _, project ->
val projectName = project?.let { " :: ${it.name} (${it.sourceDirectory.absolutePath})" } ?: ""
title = "BASE Game Editor$projectName"
}
subscribe<UpdateCompilationLogEvent> {
compilationLogItem.expanded = true
}
}
override val root = borderpane {
top = mainMenuView.root
center = tabpane {
private val tabPane = tabpane {
// FIXME
// For some reason the plain object binding does not work between tabs and mainController.openItems.
@@ -85,6 +72,28 @@ class MainView : View("BASE Game Editor") {
})
}
init {
projectContext.projectProperty.addListener { _, _, project ->
val projectName = project?.let { " :: ${it.name} (${it.sourceDirectory.absolutePath})" } ?: ""
title = "BASE Game Editor$projectName"
}
subscribe<UpdateCompilationLogEvent> {
compilationLogItem.expanded = true
}
subscribe<SelectMainViewTabEvent> { event ->
openTabs[event.targetScope]?.let {
tabPane.selectionModel.select(it)
}
}
}
override val root = borderpane {
top = mainMenuView.root
center = tabPane
left = drawer(multiselect = true) {
item("Code", expanded = false) {
this += scriptFilesView