Migrate CRLF file endings to LF
This commit is contained in:
100
editor/build.gradle
Executable file → Normal file
100
editor/build.gradle
Executable file → Normal file
@@ -1,50 +1,50 @@
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.4.10'
|
||||
id 'org.openjfx.javafxplugin' version '0.0.8'
|
||||
id 'org.springframework.boot' version "$springBootVersion"
|
||||
id 'io.spring.dependency-management' version "$springDependencyManagementVersion"
|
||||
id 'idea'
|
||||
}
|
||||
|
||||
group 'com.bartlomiejpluta.base'
|
||||
version 'unspecified'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.kotlin.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
javafx {
|
||||
version = "11.0.2"
|
||||
modules = ['javafx.controls', 'javafx.graphics']
|
||||
}
|
||||
|
||||
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "14"
|
||||
}
|
||||
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = "14"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(":proto")
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
||||
implementation "no.tornado:tornadofx:${tornadoFxVersion}"
|
||||
implementation platform("org.kordamp.ikonli:ikonli-bom:${ikonliVersion}")
|
||||
implementation 'org.kordamp.ikonli:ikonli-javafx'
|
||||
implementation 'org.kordamp.ikonli:ikonli-fontawesome-pack'
|
||||
|
||||
// Spring
|
||||
implementation 'org.springframework.boot:spring-boot-starter'
|
||||
}
|
||||
|
||||
build {
|
||||
dependsOn(":proto:build")
|
||||
}
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.4.10'
|
||||
id 'org.openjfx.javafxplugin' version '0.0.8'
|
||||
id 'org.springframework.boot' version "$springBootVersion"
|
||||
id 'io.spring.dependency-management' version "$springDependencyManagementVersion"
|
||||
id 'idea'
|
||||
}
|
||||
|
||||
group 'com.bartlomiejpluta.base'
|
||||
version 'unspecified'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.kotlin.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
javafx {
|
||||
version = "11.0.2"
|
||||
modules = ['javafx.controls', 'javafx.graphics']
|
||||
}
|
||||
|
||||
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "14"
|
||||
}
|
||||
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = "14"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(":proto")
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
||||
implementation "no.tornado:tornadofx:${tornadoFxVersion}"
|
||||
implementation platform("org.kordamp.ikonli:ikonli-bom:${ikonliVersion}")
|
||||
implementation 'org.kordamp.ikonli:ikonli-javafx'
|
||||
implementation 'org.kordamp.ikonli:ikonli-fontawesome-pack'
|
||||
|
||||
// Spring
|
||||
implementation 'org.springframework.boot:spring-boot-starter'
|
||||
}
|
||||
|
||||
build {
|
||||
dependsOn(":proto:build")
|
||||
}
|
||||
|
||||
68
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/App.kt
Executable file → Normal file
68
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/App.kt
Executable file → Normal file
@@ -1,35 +1,35 @@
|
||||
package com.bartlomiejpluta.base.editor
|
||||
|
||||
import com.bartlomiejpluta.base.editor.main.view.MainView
|
||||
import org.springframework.boot.SpringApplication
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.context.ConfigurableApplicationContext
|
||||
import tornadofx.App
|
||||
import tornadofx.DIContainer
|
||||
import tornadofx.FX
|
||||
import tornadofx.launch
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@SpringBootApplication
|
||||
open class EditorApp : App(MainView::class) {
|
||||
private lateinit var context: ConfigurableApplicationContext
|
||||
|
||||
override fun init() {
|
||||
this.context = SpringApplication.run(this.javaClass)
|
||||
context.autowireCapableBeanFactory.autowireBean(this)
|
||||
|
||||
FX.dicontainer = object : DIContainer {
|
||||
override fun <T : Any> getInstance(type: KClass<T>): T = context.getBean(type.java)
|
||||
override fun <T : Any> getInstance(type: KClass<T>, name: String): T = context.getBean(name, type.java)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
context.close()
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
launch<EditorApp>(args)
|
||||
package com.bartlomiejpluta.base.editor
|
||||
|
||||
import com.bartlomiejpluta.base.editor.main.view.MainView
|
||||
import org.springframework.boot.SpringApplication
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.context.ConfigurableApplicationContext
|
||||
import tornadofx.App
|
||||
import tornadofx.DIContainer
|
||||
import tornadofx.FX
|
||||
import tornadofx.launch
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@SpringBootApplication
|
||||
open class EditorApp : App(MainView::class) {
|
||||
private lateinit var context: ConfigurableApplicationContext
|
||||
|
||||
override fun init() {
|
||||
this.context = SpringApplication.run(this.javaClass)
|
||||
context.autowireCapableBeanFactory.autowireBean(this)
|
||||
|
||||
FX.dicontainer = object : DIContainer {
|
||||
override fun <T : Any> getInstance(type: KClass<T>): T = context.getBean(type.java)
|
||||
override fun <T : Any> getInstance(type: KClass<T>, name: String): T = context.getBean(name, type.java)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
context.close()
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
launch<EditorApp>(args)
|
||||
}
|
||||
4
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/context/UndoableContext.kt
Executable file → Normal file
4
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/context/UndoableContext.kt
Executable file → Normal file
@@ -1,3 +1,3 @@
|
||||
package com.bartlomiejpluta.base.editor.command.context
|
||||
|
||||
package com.bartlomiejpluta.base.editor.command.context
|
||||
|
||||
interface UndoableContext
|
||||
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/context/UndoableScope.kt
Executable file → Normal file
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/context/UndoableScope.kt
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
package com.bartlomiejpluta.base.editor.command.context
|
||||
|
||||
import tornadofx.Scope
|
||||
|
||||
package com.bartlomiejpluta.base.editor.command.context
|
||||
|
||||
import tornadofx.Scope
|
||||
|
||||
class UndoableScope : UndoableContext, Scope()
|
||||
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/Command.kt
Executable file → Normal file
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/Command.kt
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
package com.bartlomiejpluta.base.editor.command.model.base
|
||||
|
||||
interface Command {
|
||||
fun execute()
|
||||
package com.bartlomiejpluta.base.editor.command.model.base
|
||||
|
||||
interface Command {
|
||||
fun execute()
|
||||
}
|
||||
40
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/SimpleCommand.kt
Executable file → Normal file
40
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/SimpleCommand.kt
Executable file → Normal file
@@ -1,21 +1,21 @@
|
||||
package com.bartlomiejpluta.base.editor.command.model.base
|
||||
|
||||
class SimpleCommand<T>(
|
||||
override val commandName: String,
|
||||
private val formerValue: T,
|
||||
private val value: T,
|
||||
private val execute: (T) -> Unit
|
||||
) : Undoable, Command {
|
||||
|
||||
override fun undo() {
|
||||
execute(formerValue)
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
execute()
|
||||
}
|
||||
|
||||
override fun execute() {
|
||||
execute(value)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.command.model.base
|
||||
|
||||
class SimpleCommand<T>(
|
||||
override val commandName: String,
|
||||
private val formerValue: T,
|
||||
private val value: T,
|
||||
private val execute: (T) -> Unit
|
||||
) : Undoable, Command {
|
||||
|
||||
override fun undo() {
|
||||
execute(formerValue)
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
execute()
|
||||
}
|
||||
|
||||
override fun execute() {
|
||||
execute(value)
|
||||
}
|
||||
}
|
||||
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/Undoable.kt
Executable file → Normal file
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/base/Undoable.kt
Executable file → Normal file
@@ -1,7 +1,7 @@
|
||||
package com.bartlomiejpluta.base.editor.command.model.base
|
||||
|
||||
interface Undoable {
|
||||
fun undo()
|
||||
fun redo()
|
||||
val commandName: String
|
||||
package com.bartlomiejpluta.base.editor.command.model.base
|
||||
|
||||
interface Undoable {
|
||||
fun undo()
|
||||
fun redo()
|
||||
val commandName: String
|
||||
}
|
||||
44
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/CreateLayerCommand.kt
Executable file → Normal file
44
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/CreateLayerCommand.kt
Executable file → Normal file
@@ -1,23 +1,23 @@
|
||||
package com.bartlomiejpluta.base.editor.command.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
|
||||
class CreateLayerCommand(private val map: GameMap, private val layer: Layer): Undoable, Command {
|
||||
|
||||
override fun execute() {
|
||||
map.layers += layer
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
map.layers -= layer
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
execute()
|
||||
}
|
||||
|
||||
override val commandName = "Create map layer"
|
||||
package com.bartlomiejpluta.base.editor.command.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
|
||||
class CreateLayerCommand(private val map: GameMap, private val layer: Layer): Undoable, Command {
|
||||
|
||||
override fun execute() {
|
||||
map.layers += layer
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
map.layers -= layer
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
execute()
|
||||
}
|
||||
|
||||
override val commandName = "Create map layer"
|
||||
}
|
||||
42
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/MoveLayerCommand.kt
Executable file → Normal file
42
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/MoveLayerCommand.kt
Executable file → Normal file
@@ -1,22 +1,22 @@
|
||||
package com.bartlomiejpluta.base.editor.command.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import tornadofx.swap
|
||||
|
||||
class MoveLayerCommand(private val map: GameMap, private val currentIndex: Int, private val newIndex: Int) : Undoable, Command {
|
||||
override fun execute() {
|
||||
map.layers.swap(currentIndex, newIndex)
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
map.layers.swap(newIndex, currentIndex)
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
execute()
|
||||
}
|
||||
|
||||
override val commandName = "Move layer"
|
||||
package com.bartlomiejpluta.base.editor.command.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import tornadofx.swap
|
||||
|
||||
class MoveLayerCommand(private val map: GameMap, private val currentIndex: Int, private val newIndex: Int) : Undoable, Command {
|
||||
override fun execute() {
|
||||
map.layers.swap(currentIndex, newIndex)
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
map.layers.swap(newIndex, currentIndex)
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
execute()
|
||||
}
|
||||
|
||||
override val commandName = "Move layer"
|
||||
}
|
||||
48
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/RemoveLayerCommand.kt
Executable file → Normal file
48
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/RemoveLayerCommand.kt
Executable file → Normal file
@@ -1,25 +1,25 @@
|
||||
package com.bartlomiejpluta.base.editor.command.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
|
||||
class RemoveLayerCommand(private val map: GameMap, private val layerIndex: Int) : Undoable, Command {
|
||||
private var layer: Layer? = null
|
||||
|
||||
override fun execute() {
|
||||
layer = map.layers.removeAt(layerIndex)
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
map.layers.add(layerIndex, layer)
|
||||
layer = null
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
execute()
|
||||
}
|
||||
|
||||
override val commandName = "Remove layer"
|
||||
package com.bartlomiejpluta.base.editor.command.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
|
||||
class RemoveLayerCommand(private val map: GameMap, private val layerIndex: Int) : Undoable, Command {
|
||||
private var layer: Layer? = null
|
||||
|
||||
override fun execute() {
|
||||
layer = map.layers.removeAt(layerIndex)
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
map.layers.add(layerIndex, layer)
|
||||
layer = null
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
execute()
|
||||
}
|
||||
|
||||
override val commandName = "Remove layer"
|
||||
}
|
||||
44
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/RenameLayerCommand.kt
Executable file → Normal file
44
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/model/map/RenameLayerCommand.kt
Executable file → Normal file
@@ -1,23 +1,23 @@
|
||||
package com.bartlomiejpluta.base.editor.command.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
|
||||
class RenameLayerCommand(private val layer: Layer, private val newName: String) : Undoable, Command {
|
||||
private val formerName = layer.name
|
||||
|
||||
override fun execute() {
|
||||
layer.name = newName
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
layer.name = formerName
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
execute()
|
||||
}
|
||||
|
||||
override val commandName = "Rename layer"
|
||||
package com.bartlomiejpluta.base.editor.command.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Command
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
|
||||
class RenameLayerCommand(private val layer: Layer, private val newName: String) : Undoable, Command {
|
||||
private val formerName = layer.name
|
||||
|
||||
override fun execute() {
|
||||
layer.name = newName
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
layer.name = formerName
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
execute()
|
||||
}
|
||||
|
||||
override val commandName = "Rename layer"
|
||||
}
|
||||
242
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/service/DefaultUndoRedoService.kt
Executable file → Normal file
242
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/service/DefaultUndoRedoService.kt
Executable file → Normal file
@@ -1,122 +1,122 @@
|
||||
package com.bartlomiejpluta.base.editor.command.service
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableContext
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Component
|
||||
import java.lang.Integer.toHexString
|
||||
import java.util.*
|
||||
|
||||
@Component
|
||||
class DefaultUndoRedoService : UndoRedoService {
|
||||
private val undo: Deque<Pair<Undoable, UndoableContext>> = ArrayDeque()
|
||||
private val redo: Deque<Pair<Undoable, UndoableContext>> = ArrayDeque()
|
||||
|
||||
var sizeMax = 30
|
||||
set(value) {
|
||||
if (value >= 0) {
|
||||
for (i in 0 until undo.size - value) {
|
||||
undo.removeLast()
|
||||
}
|
||||
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
override fun push(undoable: Undoable) {
|
||||
push(undoable, GLOBAL_CONTEXT)
|
||||
}
|
||||
|
||||
override fun push(undoable: Undoable, context: UndoableContext) {
|
||||
if (undo.size == sizeMax) {
|
||||
log.debug("The max size of [undo] stack has been reached. Removing the last item...")
|
||||
undo.removeLast()
|
||||
}
|
||||
|
||||
log.debug("Pushing item to [undo] stack: ${undoable.commandName} (ctx: ${toHexString(context.hashCode())})")
|
||||
undo.push(undoable to context)
|
||||
redo.clear()
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
if (undo.isNotEmpty()) {
|
||||
undo.pop().let {
|
||||
log.debug("Performing undo: ${it.first.commandName}")
|
||||
it.first.undo()
|
||||
redo.push(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun undo(context: UndoableContext) {
|
||||
if (undo.isNotEmpty()) {
|
||||
undo.firstOrNull { it.second === context }?.let {
|
||||
log.debug("Performing contextual (ctx: ${toHexString(context.hashCode())}) undo: ${it.first.commandName}")
|
||||
undo.remove(it)
|
||||
it.first.undo()
|
||||
redo.push(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
if (redo.isNotEmpty()) {
|
||||
redo.pop().let {
|
||||
log.debug("Performing redo: ${it.first.commandName}")
|
||||
it.first.redo()
|
||||
undo.push(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun redo(context: UndoableContext) {
|
||||
if (redo.isNotEmpty()) {
|
||||
redo.firstOrNull { it.second === context }?.let {
|
||||
log.debug("Performing contextual (ctx: ${toHexString(context.hashCode())}) redo: ${it.first.commandName}")
|
||||
redo.remove(it)
|
||||
it.first.redo()
|
||||
undo.push(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
log.debug("Clearing [undo] and [redo] stacks")
|
||||
undo.clear()
|
||||
redo.clear()
|
||||
}
|
||||
|
||||
override fun clear(context: UndoableContext) {
|
||||
log.debug("Clearing [undo] and [redo] stacks (ctx: ${toHexString(context.hashCode())})")
|
||||
undo.removeIf { it.second == context }
|
||||
redo.removeIf { it.second == context }
|
||||
}
|
||||
|
||||
override val lastUndoable: Undoable?
|
||||
get() = undo.first?.first
|
||||
|
||||
override val lastRedoable: Undoable?
|
||||
get() = redo.first?.first
|
||||
|
||||
override val undoCommandName: String
|
||||
get() = undo.first?.first?.commandName ?: ""
|
||||
|
||||
override val redoCommandName: String
|
||||
get() = redo.first?.first?.commandName ?: ""
|
||||
|
||||
override fun lastUndoable(context: UndoableContext) = undo.firstOrNull { it.second === context }?.first
|
||||
|
||||
override fun lastRedoable(context: UndoableContext) = redo.firstOrNull { it.second === context }?.first
|
||||
|
||||
override fun undoCommandName(context: UndoableContext) =
|
||||
undo.firstOrNull { it.second === context }?.first?.commandName ?: ""
|
||||
|
||||
override fun redoCommandName(context: UndoableContext) =
|
||||
redo.firstOrNull { it.second === context }?.first?.commandName ?: ""
|
||||
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(DefaultUndoRedoService::class.java)
|
||||
private val GLOBAL_CONTEXT = object : UndoableContext {}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.command.service
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableContext
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Component
|
||||
import java.lang.Integer.toHexString
|
||||
import java.util.*
|
||||
|
||||
@Component
|
||||
class DefaultUndoRedoService : UndoRedoService {
|
||||
private val undo: Deque<Pair<Undoable, UndoableContext>> = ArrayDeque()
|
||||
private val redo: Deque<Pair<Undoable, UndoableContext>> = ArrayDeque()
|
||||
|
||||
var sizeMax = 30
|
||||
set(value) {
|
||||
if (value >= 0) {
|
||||
for (i in 0 until undo.size - value) {
|
||||
undo.removeLast()
|
||||
}
|
||||
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
override fun push(undoable: Undoable) {
|
||||
push(undoable, GLOBAL_CONTEXT)
|
||||
}
|
||||
|
||||
override fun push(undoable: Undoable, context: UndoableContext) {
|
||||
if (undo.size == sizeMax) {
|
||||
log.debug("The max size of [undo] stack has been reached. Removing the last item...")
|
||||
undo.removeLast()
|
||||
}
|
||||
|
||||
log.debug("Pushing item to [undo] stack: ${undoable.commandName} (ctx: ${toHexString(context.hashCode())})")
|
||||
undo.push(undoable to context)
|
||||
redo.clear()
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
if (undo.isNotEmpty()) {
|
||||
undo.pop().let {
|
||||
log.debug("Performing undo: ${it.first.commandName}")
|
||||
it.first.undo()
|
||||
redo.push(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun undo(context: UndoableContext) {
|
||||
if (undo.isNotEmpty()) {
|
||||
undo.firstOrNull { it.second === context }?.let {
|
||||
log.debug("Performing contextual (ctx: ${toHexString(context.hashCode())}) undo: ${it.first.commandName}")
|
||||
undo.remove(it)
|
||||
it.first.undo()
|
||||
redo.push(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
if (redo.isNotEmpty()) {
|
||||
redo.pop().let {
|
||||
log.debug("Performing redo: ${it.first.commandName}")
|
||||
it.first.redo()
|
||||
undo.push(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun redo(context: UndoableContext) {
|
||||
if (redo.isNotEmpty()) {
|
||||
redo.firstOrNull { it.second === context }?.let {
|
||||
log.debug("Performing contextual (ctx: ${toHexString(context.hashCode())}) redo: ${it.first.commandName}")
|
||||
redo.remove(it)
|
||||
it.first.redo()
|
||||
undo.push(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
log.debug("Clearing [undo] and [redo] stacks")
|
||||
undo.clear()
|
||||
redo.clear()
|
||||
}
|
||||
|
||||
override fun clear(context: UndoableContext) {
|
||||
log.debug("Clearing [undo] and [redo] stacks (ctx: ${toHexString(context.hashCode())})")
|
||||
undo.removeIf { it.second == context }
|
||||
redo.removeIf { it.second == context }
|
||||
}
|
||||
|
||||
override val lastUndoable: Undoable?
|
||||
get() = undo.first?.first
|
||||
|
||||
override val lastRedoable: Undoable?
|
||||
get() = redo.first?.first
|
||||
|
||||
override val undoCommandName: String
|
||||
get() = undo.first?.first?.commandName ?: ""
|
||||
|
||||
override val redoCommandName: String
|
||||
get() = redo.first?.first?.commandName ?: ""
|
||||
|
||||
override fun lastUndoable(context: UndoableContext) = undo.firstOrNull { it.second === context }?.first
|
||||
|
||||
override fun lastRedoable(context: UndoableContext) = redo.firstOrNull { it.second === context }?.first
|
||||
|
||||
override fun undoCommandName(context: UndoableContext) =
|
||||
undo.firstOrNull { it.second === context }?.first?.commandName ?: ""
|
||||
|
||||
override fun redoCommandName(context: UndoableContext) =
|
||||
redo.firstOrNull { it.second === context }?.first?.commandName ?: ""
|
||||
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(DefaultUndoRedoService::class.java)
|
||||
private val GLOBAL_CONTEXT = object : UndoableContext {}
|
||||
}
|
||||
}
|
||||
50
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/service/UndoRedoService.kt
Executable file → Normal file
50
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/command/service/UndoRedoService.kt
Executable file → Normal file
@@ -1,26 +1,26 @@
|
||||
package com.bartlomiejpluta.base.editor.command.service
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableContext
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
|
||||
interface UndoRedoService {
|
||||
fun push(undoable: Undoable)
|
||||
fun undo()
|
||||
fun redo()
|
||||
fun clear()
|
||||
|
||||
fun push(undoable: Undoable, context: UndoableContext)
|
||||
fun undo(context: UndoableContext)
|
||||
fun redo(context: UndoableContext)
|
||||
fun clear(context: UndoableContext)
|
||||
|
||||
val lastUndoable: Undoable?
|
||||
val lastRedoable: Undoable?
|
||||
val undoCommandName: String
|
||||
val redoCommandName: String
|
||||
|
||||
fun lastUndoable(context: UndoableContext): Undoable?
|
||||
fun lastRedoable(context: UndoableContext): Undoable?
|
||||
fun undoCommandName(context: UndoableContext): String
|
||||
fun redoCommandName(context: UndoableContext): String
|
||||
package com.bartlomiejpluta.base.editor.command.service
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableContext
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
|
||||
interface UndoRedoService {
|
||||
fun push(undoable: Undoable)
|
||||
fun undo()
|
||||
fun redo()
|
||||
fun clear()
|
||||
|
||||
fun push(undoable: Undoable, context: UndoableContext)
|
||||
fun undo(context: UndoableContext)
|
||||
fun redo(context: UndoableContext)
|
||||
fun clear(context: UndoableContext)
|
||||
|
||||
val lastUndoable: Undoable?
|
||||
val lastRedoable: Undoable?
|
||||
val undoCommandName: String
|
||||
val redoCommandName: String
|
||||
|
||||
fun lastUndoable(context: UndoableContext): Undoable?
|
||||
fun lastRedoable(context: UndoableContext): Undoable?
|
||||
fun undoCommandName(context: UndoableContext): String
|
||||
fun redoCommandName(context: UndoableContext): String
|
||||
}
|
||||
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Deserializer.kt
Executable file → Normal file
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Deserializer.kt
Executable file → Normal file
@@ -1,7 +1,7 @@
|
||||
package com.bartlomiejpluta.base.editor.common.serial
|
||||
|
||||
import java.io.InputStream
|
||||
|
||||
interface Deserializer<T> {
|
||||
fun deserialize(input: InputStream): T
|
||||
package com.bartlomiejpluta.base.editor.common.serial
|
||||
|
||||
import java.io.InputStream
|
||||
|
||||
interface Deserializer<T> {
|
||||
fun deserialize(input: InputStream): T
|
||||
}
|
||||
14
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Serializer.kt
Executable file → Normal file
14
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Serializer.kt
Executable file → Normal file
@@ -1,8 +1,8 @@
|
||||
package com.bartlomiejpluta.base.editor.common.serial
|
||||
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
interface Serializer<T> {
|
||||
fun serialize(item: T, output: OutputStream)
|
||||
package com.bartlomiejpluta.base.editor.common.serial
|
||||
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
interface Serializer<T> {
|
||||
fun serialize(item: T, output: OutputStream)
|
||||
}
|
||||
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/event/RedrawMapRequestEvent.kt
Executable file → Normal file
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/event/RedrawMapRequestEvent.kt
Executable file → Normal file
@@ -1,7 +1,7 @@
|
||||
package com.bartlomiejpluta.base.editor.event
|
||||
|
||||
import tornadofx.EventBus.RunOn.ApplicationThread
|
||||
import tornadofx.EventBus.RunOn.BackgroundThread
|
||||
import tornadofx.FXEvent
|
||||
|
||||
package com.bartlomiejpluta.base.editor.event
|
||||
|
||||
import tornadofx.EventBus.RunOn.ApplicationThread
|
||||
import tornadofx.EventBus.RunOn.BackgroundThread
|
||||
import tornadofx.FXEvent
|
||||
|
||||
object RedrawMapRequestEvent : FXEvent(ApplicationThread)
|
||||
116
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt
Executable file → Normal file
116
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt
Executable file → Normal file
@@ -1,59 +1,59 @@
|
||||
package com.bartlomiejpluta.base.editor.main.controller
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.editor.map.view.MapSettingsFragment
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import com.bartlomiejpluta.base.editor.project.manager.ProjectManager
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import com.bartlomiejpluta.base.editor.project.view.ProjectSettingsFragment
|
||||
import com.bartlomiejpluta.base.editor.project.viewmodel.ProjectVM
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.stage.FileChooser
|
||||
import org.springframework.stereotype.Component
|
||||
import tornadofx.*
|
||||
import kotlin.collections.set
|
||||
|
||||
@Component
|
||||
class MainController : Controller() {
|
||||
// In the future it'll be pulled from TileSetService or something like that
|
||||
private val tileset = TileSet(resources.image("/textures/tileset.png"), 160, 8)
|
||||
private val projectManager: ProjectManager by di()
|
||||
|
||||
val openProject = SimpleObjectProperty<Project?>()
|
||||
val openMaps = observableMapOf<Scope, GameMap>()
|
||||
|
||||
fun createEmptyProject() {
|
||||
val project = Project()
|
||||
val vm = ProjectVM(project)
|
||||
|
||||
setInScope(vm)
|
||||
val modal = find<ProjectSettingsFragment>().apply { openModal(block = true, resizable = false) }
|
||||
|
||||
if(modal.result) {
|
||||
openProject.value = project
|
||||
projectManager.saveProject(project)
|
||||
}
|
||||
}
|
||||
|
||||
fun createEmptyMap() {
|
||||
val map = GameMap(tileset)
|
||||
val scope = UndoableScope()
|
||||
val vm = GameMapVM(map)
|
||||
setInScope(vm, scope)
|
||||
|
||||
val modal = find<MapSettingsFragment>(scope).apply { openModal(block = true, resizable = false) }
|
||||
|
||||
if (modal.result) {
|
||||
openMaps[scope] = map
|
||||
}
|
||||
}
|
||||
|
||||
fun loadProject() {
|
||||
chooseFile(
|
||||
title = "Load Project",
|
||||
filters = arrayOf(FileChooser.ExtensionFilter("BASE Editor Project (*.bep)", "*.bep")),
|
||||
).getOrNull(0)?.let { openProject.value = projectManager.openProject(it) }
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.main.controller
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.editor.map.view.MapSettingsFragment
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import com.bartlomiejpluta.base.editor.project.manager.ProjectManager
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import com.bartlomiejpluta.base.editor.project.view.ProjectSettingsFragment
|
||||
import com.bartlomiejpluta.base.editor.project.viewmodel.ProjectVM
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.stage.FileChooser
|
||||
import org.springframework.stereotype.Component
|
||||
import tornadofx.*
|
||||
import kotlin.collections.set
|
||||
|
||||
@Component
|
||||
class MainController : Controller() {
|
||||
// In the future it'll be pulled from TileSetService or something like that
|
||||
private val tileset = TileSet(resources.image("/textures/tileset.png"), 160, 8)
|
||||
private val projectManager: ProjectManager by di()
|
||||
|
||||
val openProject = SimpleObjectProperty<Project?>()
|
||||
val openMaps = observableMapOf<Scope, GameMap>()
|
||||
|
||||
fun createEmptyProject() {
|
||||
val project = Project()
|
||||
val vm = ProjectVM(project)
|
||||
|
||||
setInScope(vm)
|
||||
val modal = find<ProjectSettingsFragment>().apply { openModal(block = true, resizable = false) }
|
||||
|
||||
if(modal.result) {
|
||||
openProject.value = project
|
||||
projectManager.saveProject(project)
|
||||
}
|
||||
}
|
||||
|
||||
fun createEmptyMap() {
|
||||
val map = GameMap(tileset)
|
||||
val scope = UndoableScope()
|
||||
val vm = GameMapVM(map)
|
||||
setInScope(vm, scope)
|
||||
|
||||
val modal = find<MapSettingsFragment>(scope).apply { openModal(block = true, resizable = false) }
|
||||
|
||||
if (modal.result) {
|
||||
openMaps[scope] = map
|
||||
}
|
||||
}
|
||||
|
||||
fun loadProject() {
|
||||
chooseFile(
|
||||
title = "Load Project",
|
||||
filters = arrayOf(FileChooser.ExtensionFilter("BASE Editor Project (*.bep)", "*.bep")),
|
||||
).getOrNull(0)?.let { openProject.value = projectManager.openProject(it) }
|
||||
}
|
||||
}
|
||||
78
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainMenuView.kt
Executable file → Normal file
78
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainMenuView.kt
Executable file → Normal file
@@ -1,40 +1,40 @@
|
||||
package com.bartlomiejpluta.base.editor.main.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.main.controller.MainController
|
||||
import tornadofx.*
|
||||
|
||||
class MainMenuView : View() {
|
||||
private val mainController: MainController by di()
|
||||
|
||||
override val root = menubar {
|
||||
menu("File") {
|
||||
menu("New") {
|
||||
item("Project...") {
|
||||
action {
|
||||
mainController.createEmptyProject()
|
||||
}
|
||||
}
|
||||
|
||||
item("Map...") {
|
||||
enableWhen(mainController.openProject.isNotNull)
|
||||
action {
|
||||
mainController.createEmptyMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menu("Open") {
|
||||
item("Project...") {
|
||||
action {
|
||||
mainController.loadProject()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menu("Edit") {
|
||||
item("Undo")
|
||||
item("Redo")
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.main.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.main.controller.MainController
|
||||
import tornadofx.*
|
||||
|
||||
class MainMenuView : View() {
|
||||
private val mainController: MainController by di()
|
||||
|
||||
override val root = menubar {
|
||||
menu("File") {
|
||||
menu("New") {
|
||||
item("Project...") {
|
||||
action {
|
||||
mainController.createEmptyProject()
|
||||
}
|
||||
}
|
||||
|
||||
item("Map...") {
|
||||
enableWhen(mainController.openProject.isNotNull)
|
||||
action {
|
||||
mainController.createEmptyMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menu("Open") {
|
||||
item("Project...") {
|
||||
action {
|
||||
mainController.loadProject()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menu("Edit") {
|
||||
item("Undo")
|
||||
item("Redo")
|
||||
}
|
||||
}
|
||||
}
|
||||
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainView.kt
Executable file → Normal file
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/view/MainView.kt
Executable file → Normal file
@@ -1,34 +1,34 @@
|
||||
package com.bartlomiejpluta.base.editor.main.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.main.controller.MainController
|
||||
import com.bartlomiejpluta.base.editor.map.view.MapFragment
|
||||
import javafx.scene.control.Tab
|
||||
import tornadofx.*
|
||||
|
||||
|
||||
class MainView : View("BASE Game Editor") {
|
||||
private val mainController: MainController by di()
|
||||
|
||||
private val mainMenuView = find<MainMenuView>()
|
||||
|
||||
init {
|
||||
mainController.openProject.addListener { _, _, project ->
|
||||
val projectName = project?.let { " :: ${it.name} (${it.sourceDirectory.absolutePath})" } ?: ""
|
||||
title = "BASE Game Editor$projectName"
|
||||
}
|
||||
}
|
||||
|
||||
override val root = borderpane {
|
||||
top = mainMenuView.root
|
||||
|
||||
center = tabpane {
|
||||
tabs.bind(mainController.openMaps) { scope, map ->
|
||||
Tab().apply {
|
||||
textProperty().bindBidirectional(map.nameProperty)
|
||||
content = find<MapFragment>(scope).root
|
||||
setOnClosed { mainController.openMaps.remove(scope) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.main.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.main.controller.MainController
|
||||
import com.bartlomiejpluta.base.editor.map.view.MapFragment
|
||||
import javafx.scene.control.Tab
|
||||
import tornadofx.*
|
||||
|
||||
|
||||
class MainView : View("BASE Game Editor") {
|
||||
private val mainController: MainController by di()
|
||||
|
||||
private val mainMenuView = find<MainMenuView>()
|
||||
|
||||
init {
|
||||
mainController.openProject.addListener { _, _, project ->
|
||||
val projectName = project?.let { " :: ${it.name} (${it.sourceDirectory.absolutePath})" } ?: ""
|
||||
title = "BASE Game Editor$projectName"
|
||||
}
|
||||
}
|
||||
|
||||
override val root = borderpane {
|
||||
top = mainMenuView.root
|
||||
|
||||
center = tabpane {
|
||||
tabs.bind(mainController.openMaps) { scope, map ->
|
||||
Tab().apply {
|
||||
textProperty().bindBidirectional(map.nameProperty)
|
||||
content = find<MapFragment>(scope).root
|
||||
setOnClosed { mainController.openMaps.remove(scope) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
194
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt
Executable file → Normal file
194
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt
Executable file → Normal file
@@ -1,98 +1,98 @@
|
||||
package com.bartlomiejpluta.base.editor.map.canvas
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
import javafx.scene.paint.Color
|
||||
|
||||
|
||||
class MapCanvas(val map: GameMapVM, private val editorStateVM: EditorStateVM, private val painter: MapPainter) : Renderable {
|
||||
var tileSet = map.tileSet
|
||||
private var tileWidth = map.tileWidth
|
||||
private var tileHeight = map.tileHeight
|
||||
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
gc.clearRect(0.0, 0.0, gc.canvas.width, gc.canvas.height)
|
||||
|
||||
renderBackground(gc)
|
||||
renderUnderlyingLayers(gc)
|
||||
renderCover(gc)
|
||||
renderSelectedLayer(gc)
|
||||
renderGrid(gc)
|
||||
painter.render(gc)
|
||||
}
|
||||
|
||||
private fun renderSelectedLayer(gc: GraphicsContext) {
|
||||
map.layers.getOrNull(editorStateVM.selectedLayer) ?. let { dispatchLayerRender(gc, it) }
|
||||
}
|
||||
|
||||
private fun renderCover(gc: GraphicsContext) {
|
||||
if(!editorStateVM.coverUnderlyingLayers) {
|
||||
return
|
||||
}
|
||||
|
||||
gc.fill = Color.color(0.0, 0.0, 0.0, 0.4)
|
||||
gc.fillRect(0.0, 0.0, map.width, map.height)
|
||||
}
|
||||
|
||||
private fun renderUnderlyingLayers(gc: GraphicsContext) {
|
||||
for(layer in map.layers.dropLast(if(editorStateVM.selectedLayer < 0) 0 else map.layers.size - editorStateVM.selectedLayer)) {
|
||||
dispatchLayerRender(gc, layer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dispatchLayerRender(gc: GraphicsContext, layer: Layer) {
|
||||
when (layer) {
|
||||
is TileLayer -> renderTileLayer(gc, layer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderBackground(gc: GraphicsContext) {
|
||||
for (row in 0 until map.rows) {
|
||||
for (column in 0 until map.columns) {
|
||||
gc.fill = if ((row + column) % 2 == 0) BACKGROUND_COLOR1 else BACKGROUND_COLOR2
|
||||
gc.fillRect(column * tileWidth, row * tileHeight, tileWidth, tileHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderTileLayer(gc: GraphicsContext, tileLayer: TileLayer) {
|
||||
for ((row, columns) in tileLayer.layer.withIndex()) {
|
||||
for ((column, tile) in columns.withIndex()) {
|
||||
if (tile != null) {
|
||||
gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderGrid(gc: GraphicsContext) {
|
||||
if(!editorStateVM.showGrid) {
|
||||
return
|
||||
}
|
||||
|
||||
gc.lineWidth = 1.5
|
||||
|
||||
gc.strokeLine(0.0, 0.0, map.width, 0.0)
|
||||
gc.strokeLine(0.0, 0.0, 0.0, map.height)
|
||||
gc.strokeLine(map.width, 0.0, map.width, map.height)
|
||||
gc.strokeLine(0.0, map.height, map.width, map.height)
|
||||
|
||||
for (row in 0 until map.rows) {
|
||||
gc.strokeLine(0.0, row * tileHeight, map.width, row * tileHeight)
|
||||
}
|
||||
|
||||
for (column in 0 until map.columns) {
|
||||
gc.strokeLine(column * tileWidth, 0.0, column * tileWidth, map.height)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val BACKGROUND_COLOR1 = Color.color(1.0, 1.0, 1.0, 1.0)
|
||||
private val BACKGROUND_COLOR2 = Color.color(0.8, 0.8, 0.8, 1.0)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.canvas
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
import javafx.scene.paint.Color
|
||||
|
||||
|
||||
class MapCanvas(val map: GameMapVM, private val editorStateVM: EditorStateVM, private val painter: MapPainter) : Renderable {
|
||||
var tileSet = map.tileSet
|
||||
private var tileWidth = map.tileWidth
|
||||
private var tileHeight = map.tileHeight
|
||||
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
gc.clearRect(0.0, 0.0, gc.canvas.width, gc.canvas.height)
|
||||
|
||||
renderBackground(gc)
|
||||
renderUnderlyingLayers(gc)
|
||||
renderCover(gc)
|
||||
renderSelectedLayer(gc)
|
||||
renderGrid(gc)
|
||||
painter.render(gc)
|
||||
}
|
||||
|
||||
private fun renderSelectedLayer(gc: GraphicsContext) {
|
||||
map.layers.getOrNull(editorStateVM.selectedLayer) ?. let { dispatchLayerRender(gc, it) }
|
||||
}
|
||||
|
||||
private fun renderCover(gc: GraphicsContext) {
|
||||
if(!editorStateVM.coverUnderlyingLayers) {
|
||||
return
|
||||
}
|
||||
|
||||
gc.fill = Color.color(0.0, 0.0, 0.0, 0.4)
|
||||
gc.fillRect(0.0, 0.0, map.width, map.height)
|
||||
}
|
||||
|
||||
private fun renderUnderlyingLayers(gc: GraphicsContext) {
|
||||
for(layer in map.layers.dropLast(if(editorStateVM.selectedLayer < 0) 0 else map.layers.size - editorStateVM.selectedLayer)) {
|
||||
dispatchLayerRender(gc, layer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dispatchLayerRender(gc: GraphicsContext, layer: Layer) {
|
||||
when (layer) {
|
||||
is TileLayer -> renderTileLayer(gc, layer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderBackground(gc: GraphicsContext) {
|
||||
for (row in 0 until map.rows) {
|
||||
for (column in 0 until map.columns) {
|
||||
gc.fill = if ((row + column) % 2 == 0) BACKGROUND_COLOR1 else BACKGROUND_COLOR2
|
||||
gc.fillRect(column * tileWidth, row * tileHeight, tileWidth, tileHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderTileLayer(gc: GraphicsContext, tileLayer: TileLayer) {
|
||||
for ((row, columns) in tileLayer.layer.withIndex()) {
|
||||
for ((column, tile) in columns.withIndex()) {
|
||||
if (tile != null) {
|
||||
gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderGrid(gc: GraphicsContext) {
|
||||
if(!editorStateVM.showGrid) {
|
||||
return
|
||||
}
|
||||
|
||||
gc.lineWidth = 1.5
|
||||
|
||||
gc.strokeLine(0.0, 0.0, map.width, 0.0)
|
||||
gc.strokeLine(0.0, 0.0, 0.0, map.height)
|
||||
gc.strokeLine(map.width, 0.0, map.width, map.height)
|
||||
gc.strokeLine(0.0, map.height, map.width, map.height)
|
||||
|
||||
for (row in 0 until map.rows) {
|
||||
gc.strokeLine(0.0, row * tileHeight, map.width, row * tileHeight)
|
||||
}
|
||||
|
||||
for (column in 0 until map.columns) {
|
||||
gc.strokeLine(column * tileWidth, 0.0, column * tileWidth, map.height)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val BACKGROUND_COLOR1 = Color.color(1.0, 1.0, 1.0, 1.0)
|
||||
private val BACKGROUND_COLOR2 = Color.color(0.8, 0.8, 0.8, 1.0)
|
||||
}
|
||||
}
|
||||
186
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPainter.kt
Executable file → Normal file
186
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPainter.kt
Executable file → Normal file
@@ -1,94 +1,94 @@
|
||||
package com.bartlomiejpluta.base.editor.map.canvas
|
||||
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEventHandler
|
||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
import javafx.scene.input.MouseButton
|
||||
import javafx.scene.input.MouseEvent
|
||||
import javafx.scene.paint.Color
|
||||
|
||||
class MapPainter(
|
||||
private val mapVM: GameMapVM,
|
||||
private val brushVM: BrushVM,
|
||||
private val editorStateVM: EditorStateVM,
|
||||
private val paintingCallback: (MapPaintingTrace) -> Unit
|
||||
) : Renderable, MapMouseEventHandler {
|
||||
private val tileWidth = mapVM.tileSet.tileWidth.toDouble()
|
||||
private val tileHeight = mapVM.tileSet.tileHeight.toDouble()
|
||||
|
||||
private var currentTrace: MapPaintingTrace? = null
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
val alpha = gc.globalAlpha
|
||||
gc.globalAlpha = 0.4
|
||||
|
||||
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
||||
renderTile(gc, row, column, centerRow, centerColumn, tile)
|
||||
}
|
||||
|
||||
gc.globalAlpha = alpha
|
||||
}
|
||||
|
||||
private fun renderTile(gc: GraphicsContext, row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) {
|
||||
val x = tileWidth * (editorStateVM.cursorColumn - centerColumn + column)
|
||||
val y = tileHeight * (editorStateVM.cursorRow - centerRow + row)
|
||||
|
||||
when {
|
||||
tile != null -> renderPaintingBrushTile(gc, tile, x, y)
|
||||
else -> renderEraserTile(gc, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderPaintingBrushTile(gc: GraphicsContext, tile: Tile, x: Double, y: Double) =
|
||||
gc.drawImage(tile.image, x, y)
|
||||
|
||||
private fun renderEraserTile(gc: GraphicsContext, x: Double, y: Double) {
|
||||
gc.fill = Color.WHITE
|
||||
gc.fillRect(x, y, tileWidth, tileHeight)
|
||||
}
|
||||
|
||||
override fun handleMouseInput(event: MapMouseEvent) {
|
||||
editorStateVM.cursorRowProperty.value = event.row
|
||||
editorStateVM.cursorColumnProperty.value = event.column
|
||||
|
||||
when (event.type) {
|
||||
MouseEvent.MOUSE_PRESSED -> beginTrace(event)
|
||||
MouseEvent.MOUSE_DRAGGED -> proceedTrace(event)
|
||||
MouseEvent.MOUSE_RELEASED -> commitTrace(event)
|
||||
}
|
||||
}
|
||||
|
||||
private fun beginTrace(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY && editorStateVM.selectedLayer >= 0) {
|
||||
currentTrace = MapPaintingTrace(mapVM, "Paint trace").apply {
|
||||
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
||||
paint(editorStateVM.selectedLayer, editorStateVM.cursorRow - centerRow + row, editorStateVM.cursorColumn - centerColumn + column, tile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedTrace(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY) {
|
||||
currentTrace?.apply {
|
||||
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
||||
paint(editorStateVM.selectedLayer, editorStateVM.cursorRow - centerRow + row, editorStateVM.cursorColumn - centerColumn + column, tile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun commitTrace(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY) {
|
||||
currentTrace?.let {
|
||||
paintingCallback(it)
|
||||
currentTrace = null
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.canvas
|
||||
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEventHandler
|
||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
import javafx.scene.input.MouseButton
|
||||
import javafx.scene.input.MouseEvent
|
||||
import javafx.scene.paint.Color
|
||||
|
||||
class MapPainter(
|
||||
private val mapVM: GameMapVM,
|
||||
private val brushVM: BrushVM,
|
||||
private val editorStateVM: EditorStateVM,
|
||||
private val paintingCallback: (MapPaintingTrace) -> Unit
|
||||
) : Renderable, MapMouseEventHandler {
|
||||
private val tileWidth = mapVM.tileSet.tileWidth.toDouble()
|
||||
private val tileHeight = mapVM.tileSet.tileHeight.toDouble()
|
||||
|
||||
private var currentTrace: MapPaintingTrace? = null
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
val alpha = gc.globalAlpha
|
||||
gc.globalAlpha = 0.4
|
||||
|
||||
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
||||
renderTile(gc, row, column, centerRow, centerColumn, tile)
|
||||
}
|
||||
|
||||
gc.globalAlpha = alpha
|
||||
}
|
||||
|
||||
private fun renderTile(gc: GraphicsContext, row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) {
|
||||
val x = tileWidth * (editorStateVM.cursorColumn - centerColumn + column)
|
||||
val y = tileHeight * (editorStateVM.cursorRow - centerRow + row)
|
||||
|
||||
when {
|
||||
tile != null -> renderPaintingBrushTile(gc, tile, x, y)
|
||||
else -> renderEraserTile(gc, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderPaintingBrushTile(gc: GraphicsContext, tile: Tile, x: Double, y: Double) =
|
||||
gc.drawImage(tile.image, x, y)
|
||||
|
||||
private fun renderEraserTile(gc: GraphicsContext, x: Double, y: Double) {
|
||||
gc.fill = Color.WHITE
|
||||
gc.fillRect(x, y, tileWidth, tileHeight)
|
||||
}
|
||||
|
||||
override fun handleMouseInput(event: MapMouseEvent) {
|
||||
editorStateVM.cursorRowProperty.value = event.row
|
||||
editorStateVM.cursorColumnProperty.value = event.column
|
||||
|
||||
when (event.type) {
|
||||
MouseEvent.MOUSE_PRESSED -> beginTrace(event)
|
||||
MouseEvent.MOUSE_DRAGGED -> proceedTrace(event)
|
||||
MouseEvent.MOUSE_RELEASED -> commitTrace(event)
|
||||
}
|
||||
}
|
||||
|
||||
private fun beginTrace(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY && editorStateVM.selectedLayer >= 0) {
|
||||
currentTrace = MapPaintingTrace(mapVM, "Paint trace").apply {
|
||||
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
||||
paint(editorStateVM.selectedLayer, editorStateVM.cursorRow - centerRow + row, editorStateVM.cursorColumn - centerColumn + column, tile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedTrace(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY) {
|
||||
currentTrace?.apply {
|
||||
brushVM.forEach { row, column, centerRow, centerColumn, tile ->
|
||||
paint(editorStateVM.selectedLayer, editorStateVM.cursorRow - centerRow + row, editorStateVM.cursorColumn - centerColumn + column, tile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun commitTrace(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY) {
|
||||
currentTrace?.let {
|
||||
paintingCallback(it)
|
||||
currentTrace = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPaintingTrace.kt
Executable file → Normal file
110
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPaintingTrace.kt
Executable file → Normal file
@@ -1,56 +1,56 @@
|
||||
package com.bartlomiejpluta.base.editor.map.canvas
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
|
||||
|
||||
data class MapPaintingTrace(val map: GameMapVM, override val commandName: String) : Undoable {
|
||||
private val trace = mutableListOf<Element>()
|
||||
|
||||
fun paint(layerIndex: Int, row: Int, column: Int, tile: Tile?) {
|
||||
if (row >= map.rows || column >= map.columns || row < 0 || column < 0 || layerIndex < 0) {
|
||||
return
|
||||
}
|
||||
|
||||
val layer = (map.layers[layerIndex] as TileLayer).layer
|
||||
val formerTile = layer[row][column]
|
||||
|
||||
if (trace.isEmpty()) {
|
||||
trace += Element(layerIndex, row, column, formerTile, tile)
|
||||
layer[row][column] = tile
|
||||
return
|
||||
}
|
||||
|
||||
val tileAlreadyPainted =
|
||||
trace.find { it.layerIndex == layerIndex && it.row == row && it.column == column } != null
|
||||
|
||||
if (!tileAlreadyPainted) {
|
||||
trace += Element(layerIndex, row, column, formerTile, tile)
|
||||
layer[row][column] = tile
|
||||
}
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
trace.forEach {
|
||||
(map.layers[it.layerIndex] as TileLayer).layer[it.row][it.column] = it.formerTile
|
||||
}
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
trace.forEach {
|
||||
(map.layers[it.layerIndex] as TileLayer).layer[it.row][it.column] = it.tile
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private data class Element(
|
||||
val layerIndex: Int,
|
||||
val row: Int,
|
||||
val column: Int,
|
||||
val formerTile: Tile?,
|
||||
val tile: Tile?
|
||||
)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.canvas
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.model.base.Undoable
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
|
||||
|
||||
data class MapPaintingTrace(val map: GameMapVM, override val commandName: String) : Undoable {
|
||||
private val trace = mutableListOf<Element>()
|
||||
|
||||
fun paint(layerIndex: Int, row: Int, column: Int, tile: Tile?) {
|
||||
if (row >= map.rows || column >= map.columns || row < 0 || column < 0 || layerIndex < 0) {
|
||||
return
|
||||
}
|
||||
|
||||
val layer = (map.layers[layerIndex] as TileLayer).layer
|
||||
val formerTile = layer[row][column]
|
||||
|
||||
if (trace.isEmpty()) {
|
||||
trace += Element(layerIndex, row, column, formerTile, tile)
|
||||
layer[row][column] = tile
|
||||
return
|
||||
}
|
||||
|
||||
val tileAlreadyPainted =
|
||||
trace.find { it.layerIndex == layerIndex && it.row == row && it.column == column } != null
|
||||
|
||||
if (!tileAlreadyPainted) {
|
||||
trace += Element(layerIndex, row, column, formerTile, tile)
|
||||
layer[row][column] = tile
|
||||
}
|
||||
}
|
||||
|
||||
override fun undo() {
|
||||
trace.forEach {
|
||||
(map.layers[it.layerIndex] as TileLayer).layer[it.row][it.column] = it.formerTile
|
||||
}
|
||||
}
|
||||
|
||||
override fun redo() {
|
||||
trace.forEach {
|
||||
(map.layers[it.layerIndex] as TileLayer).layer[it.row][it.column] = it.tile
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private data class Element(
|
||||
val layerIndex: Int,
|
||||
val row: Int,
|
||||
val column: Int,
|
||||
val formerTile: Tile?,
|
||||
val tile: Tile?
|
||||
)
|
||||
}
|
||||
}
|
||||
104
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/component/MapPane.kt
Executable file → Normal file
104
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/component/MapPane.kt
Executable file → Normal file
@@ -1,53 +1,53 @@
|
||||
package com.bartlomiejpluta.base.editor.map.component
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.canvas.MapCanvas
|
||||
import com.bartlomiejpluta.base.editor.map.canvas.MapPainter
|
||||
import com.bartlomiejpluta.base.editor.map.canvas.MapPaintingTrace
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.event.EventHandler
|
||||
import javafx.scene.canvas.Canvas
|
||||
import javafx.scene.input.MouseEvent
|
||||
|
||||
class MapPane(
|
||||
private val mapVM: GameMapVM,
|
||||
brushVM: BrushVM,
|
||||
editorStateVM: EditorStateVM,
|
||||
paintingCallback: (MapPaintingTrace) -> Unit
|
||||
) : Canvas(), EventHandler<MouseEvent> {
|
||||
private val painter = MapPainter(mapVM, brushVM, editorStateVM, paintingCallback)
|
||||
private val mapCanvas = MapCanvas(mapVM, editorStateVM, painter)
|
||||
|
||||
init {
|
||||
onMouseMoved = this
|
||||
onMouseDragged = this
|
||||
onMousePressed = this
|
||||
onMouseReleased = this
|
||||
|
||||
widthProperty().bind(mapVM.widthProperty)
|
||||
heightProperty().bind(mapVM.heightProperty)
|
||||
|
||||
mapVM.item.rowsProperty.addListener { _, _, _ -> render() }
|
||||
mapVM.item.columnsProperty.addListener { _, _, _ -> render() }
|
||||
|
||||
editorStateVM.showGridProperty.addListener { _, _, _ -> render() }
|
||||
editorStateVM.selectedLayerProperty.addListener { _, _, _ -> render() }
|
||||
editorStateVM.coverUnderlyingLayersProperty.addListener { _, _, _ -> render() }
|
||||
|
||||
render()
|
||||
}
|
||||
|
||||
fun render() {
|
||||
mapCanvas.render(graphicsContext2D)
|
||||
}
|
||||
|
||||
override fun handle(event: MouseEvent?) {
|
||||
if (event != null) {
|
||||
painter.handleMouseInput(MapMouseEvent.of(event, mapVM.tileSet))
|
||||
}
|
||||
|
||||
mapCanvas.render(graphicsContext2D)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.component
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.canvas.MapCanvas
|
||||
import com.bartlomiejpluta.base.editor.map.canvas.MapPainter
|
||||
import com.bartlomiejpluta.base.editor.map.canvas.MapPaintingTrace
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.event.EventHandler
|
||||
import javafx.scene.canvas.Canvas
|
||||
import javafx.scene.input.MouseEvent
|
||||
|
||||
class MapPane(
|
||||
private val mapVM: GameMapVM,
|
||||
brushVM: BrushVM,
|
||||
editorStateVM: EditorStateVM,
|
||||
paintingCallback: (MapPaintingTrace) -> Unit
|
||||
) : Canvas(), EventHandler<MouseEvent> {
|
||||
private val painter = MapPainter(mapVM, brushVM, editorStateVM, paintingCallback)
|
||||
private val mapCanvas = MapCanvas(mapVM, editorStateVM, painter)
|
||||
|
||||
init {
|
||||
onMouseMoved = this
|
||||
onMouseDragged = this
|
||||
onMousePressed = this
|
||||
onMouseReleased = this
|
||||
|
||||
widthProperty().bind(mapVM.widthProperty)
|
||||
heightProperty().bind(mapVM.heightProperty)
|
||||
|
||||
mapVM.item.rowsProperty.addListener { _, _, _ -> render() }
|
||||
mapVM.item.columnsProperty.addListener { _, _, _ -> render() }
|
||||
|
||||
editorStateVM.showGridProperty.addListener { _, _, _ -> render() }
|
||||
editorStateVM.selectedLayerProperty.addListener { _, _, _ -> render() }
|
||||
editorStateVM.coverUnderlyingLayersProperty.addListener { _, _, _ -> render() }
|
||||
|
||||
render()
|
||||
}
|
||||
|
||||
fun render() {
|
||||
mapCanvas.render(graphicsContext2D)
|
||||
}
|
||||
|
||||
override fun handle(event: MouseEvent?) {
|
||||
if (event != null) {
|
||||
painter.handleMouseInput(MapMouseEvent.of(event, mapVM.tileSet))
|
||||
}
|
||||
|
||||
mapCanvas.render(graphicsContext2D)
|
||||
}
|
||||
}
|
||||
194
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/brush/Brush.kt
Executable file → Normal file
194
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/brush/Brush.kt
Executable file → Normal file
@@ -1,97 +1,97 @@
|
||||
package com.bartlomiejpluta.base.editor.map.model.brush
|
||||
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.collections.ObservableList
|
||||
import tornadofx.asObservable
|
||||
import tornadofx.getValue
|
||||
import tornadofx.observableListOf
|
||||
import tornadofx.setValue
|
||||
|
||||
class Brush {
|
||||
val brush: ObservableList<Tile>
|
||||
|
||||
val rowsProperty = SimpleIntegerProperty(0)
|
||||
var rows by rowsProperty
|
||||
private set
|
||||
|
||||
val columnsProperty = SimpleIntegerProperty(0)
|
||||
var columns by columnsProperty
|
||||
private set
|
||||
|
||||
val rangeProperty = SimpleIntegerProperty(1)
|
||||
var range by rangeProperty
|
||||
private set
|
||||
|
||||
val modeProperty = SimpleObjectProperty(BrushMode.PAINTING_MODE)
|
||||
var mode by modeProperty
|
||||
private set
|
||||
|
||||
private constructor(brushArray: Array<Array<Tile>>) {
|
||||
rowsProperty.value = brushArray.size
|
||||
|
||||
brush = observableListOf()
|
||||
|
||||
brushArray.forEach { brush.addAll(it) }
|
||||
|
||||
if (rowsProperty.value > 0) {
|
||||
columns = brush.size / rowsProperty.value
|
||||
}
|
||||
}
|
||||
|
||||
private constructor(brush: List<Tile>, rows: Int, columns: Int) {
|
||||
this.rows = rows
|
||||
this.columns = columns
|
||||
|
||||
this.brush = brush.asObservable()
|
||||
}
|
||||
|
||||
fun forEach(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
||||
return when {
|
||||
range > 1 || mode == BrushMode.ERASING_MODE -> forEachInRangedBrush(consumer)
|
||||
else -> forEachInRegularBrush(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun forEachInRangedBrush(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
||||
val center = range / 2
|
||||
|
||||
(0 until range).forEach { row ->
|
||||
(0 until range).forEach { column ->
|
||||
consumer(row, column, center, center, getTileByMode(brush[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTileByMode(tile: Tile) = when (mode) {
|
||||
BrushMode.PAINTING_MODE -> tile
|
||||
BrushMode.ERASING_MODE -> null
|
||||
}
|
||||
|
||||
private fun forEachInRegularBrush(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
||||
val centerRow = rows / 2
|
||||
val centerColumn = columns / 2
|
||||
|
||||
brush.forEachIndexed { id, tile ->
|
||||
consumer(id / columns, id % columns, centerRow, centerColumn, getTileByMode(tile))
|
||||
}
|
||||
}
|
||||
|
||||
private fun clone() = Brush(brush, rows, columns).apply {
|
||||
this.range = this@Brush.range
|
||||
this.mode = this@Brush.mode
|
||||
}
|
||||
|
||||
fun withRange(range: Int) = clone().apply {
|
||||
this.range = range
|
||||
}
|
||||
|
||||
fun withMode(mode: BrushMode) = clone().apply {
|
||||
this.mode = mode
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun of(brushArray: Array<Array<Tile>>) = Brush(brushArray)
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.model.brush
|
||||
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.collections.ObservableList
|
||||
import tornadofx.asObservable
|
||||
import tornadofx.getValue
|
||||
import tornadofx.observableListOf
|
||||
import tornadofx.setValue
|
||||
|
||||
class Brush {
|
||||
val brush: ObservableList<Tile>
|
||||
|
||||
val rowsProperty = SimpleIntegerProperty(0)
|
||||
var rows by rowsProperty
|
||||
private set
|
||||
|
||||
val columnsProperty = SimpleIntegerProperty(0)
|
||||
var columns by columnsProperty
|
||||
private set
|
||||
|
||||
val rangeProperty = SimpleIntegerProperty(1)
|
||||
var range by rangeProperty
|
||||
private set
|
||||
|
||||
val modeProperty = SimpleObjectProperty(BrushMode.PAINTING_MODE)
|
||||
var mode by modeProperty
|
||||
private set
|
||||
|
||||
private constructor(brushArray: Array<Array<Tile>>) {
|
||||
rowsProperty.value = brushArray.size
|
||||
|
||||
brush = observableListOf()
|
||||
|
||||
brushArray.forEach { brush.addAll(it) }
|
||||
|
||||
if (rowsProperty.value > 0) {
|
||||
columns = brush.size / rowsProperty.value
|
||||
}
|
||||
}
|
||||
|
||||
private constructor(brush: List<Tile>, rows: Int, columns: Int) {
|
||||
this.rows = rows
|
||||
this.columns = columns
|
||||
|
||||
this.brush = brush.asObservable()
|
||||
}
|
||||
|
||||
fun forEach(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
||||
return when {
|
||||
range > 1 || mode == BrushMode.ERASING_MODE -> forEachInRangedBrush(consumer)
|
||||
else -> forEachInRegularBrush(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun forEachInRangedBrush(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
||||
val center = range / 2
|
||||
|
||||
(0 until range).forEach { row ->
|
||||
(0 until range).forEach { column ->
|
||||
consumer(row, column, center, center, getTileByMode(brush[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTileByMode(tile: Tile) = when (mode) {
|
||||
BrushMode.PAINTING_MODE -> tile
|
||||
BrushMode.ERASING_MODE -> null
|
||||
}
|
||||
|
||||
private fun forEachInRegularBrush(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) {
|
||||
val centerRow = rows / 2
|
||||
val centerColumn = columns / 2
|
||||
|
||||
brush.forEachIndexed { id, tile ->
|
||||
consumer(id / columns, id % columns, centerRow, centerColumn, getTileByMode(tile))
|
||||
}
|
||||
}
|
||||
|
||||
private fun clone() = Brush(brush, rows, columns).apply {
|
||||
this.range = this@Brush.range
|
||||
this.mode = this@Brush.mode
|
||||
}
|
||||
|
||||
fun withRange(range: Int) = clone().apply {
|
||||
this.range = range
|
||||
}
|
||||
|
||||
fun withMode(mode: BrushMode) = clone().apply {
|
||||
this.mode = mode
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun of(brushArray: Array<Array<Tile>>) = Brush(brushArray)
|
||||
}
|
||||
}
|
||||
|
||||
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/brush/BrushMode.kt
Executable file → Normal file
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/brush/BrushMode.kt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
package com.bartlomiejpluta.base.editor.map.model.brush
|
||||
|
||||
enum class BrushMode {
|
||||
PAINTING_MODE,
|
||||
ERASING_MODE
|
||||
package com.bartlomiejpluta.base.editor.map.model.brush
|
||||
|
||||
enum class BrushMode {
|
||||
PAINTING_MODE,
|
||||
ERASING_MODE
|
||||
}
|
||||
22
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/Layer.kt
Executable file → Normal file
22
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/Layer.kt
Executable file → Normal file
@@ -1,12 +1,12 @@
|
||||
package com.bartlomiejpluta.base.editor.map.model.layer
|
||||
|
||||
import javafx.beans.property.StringProperty
|
||||
|
||||
interface Layer {
|
||||
var name: String
|
||||
val nameProperty: StringProperty
|
||||
|
||||
fun resize(rows: Int, columns: Int)
|
||||
|
||||
fun clone(): Layer
|
||||
package com.bartlomiejpluta.base.editor.map.model.layer
|
||||
|
||||
import javafx.beans.property.StringProperty
|
||||
|
||||
interface Layer {
|
||||
var name: String
|
||||
val nameProperty: StringProperty
|
||||
|
||||
fun resize(rows: Int, columns: Int)
|
||||
|
||||
fun clone(): Layer
|
||||
}
|
||||
60
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt
Executable file → Normal file
60
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt
Executable file → Normal file
@@ -1,31 +1,31 @@
|
||||
package com.bartlomiejpluta.base.editor.map.model.layer
|
||||
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.getValue
|
||||
import tornadofx.setValue
|
||||
|
||||
class TileLayer(
|
||||
name: String,
|
||||
rows: Int,
|
||||
columns: Int,
|
||||
layer: Array<Array<Tile?>> = Array(rows) { Array(columns) { null } }
|
||||
) : Layer {
|
||||
var layer = layer
|
||||
private set
|
||||
|
||||
override val nameProperty = SimpleStringProperty(name)
|
||||
override var name: String by nameProperty
|
||||
|
||||
override fun resize(rows: Int, columns: Int) {
|
||||
layer = Array(rows) { row ->
|
||||
Array(columns) { column ->
|
||||
layer.getOrNull(row)?.getOrNull(column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun clone() = TileLayer(name, 0, 0).apply {
|
||||
layer = this@TileLayer.layer
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.model.layer
|
||||
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.getValue
|
||||
import tornadofx.setValue
|
||||
|
||||
class TileLayer(
|
||||
name: String,
|
||||
rows: Int,
|
||||
columns: Int,
|
||||
layer: Array<Array<Tile?>> = Array(rows) { Array(columns) { null } }
|
||||
) : Layer {
|
||||
var layer = layer
|
||||
private set
|
||||
|
||||
override val nameProperty = SimpleStringProperty(name)
|
||||
override var name: String by nameProperty
|
||||
|
||||
override fun resize(rows: Int, columns: Int) {
|
||||
layer = Array(rows) { row ->
|
||||
Array(columns) { column ->
|
||||
layer.getOrNull(row)?.getOrNull(column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun clone() = TileLayer(name, 0, 0).apply {
|
||||
layer = this@TileLayer.layer
|
||||
}
|
||||
}
|
||||
108
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt
Executable file → Normal file
108
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt
Executable file → Normal file
@@ -1,54 +1,54 @@
|
||||
package com.bartlomiejpluta.base.editor.map.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||
import javafx.beans.property.SimpleDoubleProperty
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.getValue
|
||||
import tornadofx.observableListOf
|
||||
import tornadofx.setValue
|
||||
|
||||
|
||||
class GameMap(val tileSet: TileSet) {
|
||||
val layers = observableListOf<Layer>()
|
||||
|
||||
val nameProperty = SimpleStringProperty()
|
||||
var name by nameProperty
|
||||
|
||||
val tileWidth = tileSet.tileWidth.toDouble()
|
||||
val tileHeight = tileSet.tileHeight.toDouble()
|
||||
|
||||
val rowsProperty = SimpleIntegerProperty(INITIAL_ROWS)
|
||||
var rows by rowsProperty
|
||||
|
||||
val columnsProperty = SimpleIntegerProperty(INITIAL_COLUMNS)
|
||||
var columns by columnsProperty
|
||||
|
||||
val widthProperty = SimpleDoubleProperty(INITIAL_COLUMNS * tileWidth)
|
||||
var width by widthProperty
|
||||
private set
|
||||
|
||||
val heightProperty = SimpleDoubleProperty(INITIAL_ROWS * tileHeight)
|
||||
var height by heightProperty
|
||||
private set
|
||||
|
||||
init {
|
||||
rowsProperty.addListener { _, _, newValue ->
|
||||
val newRows = newValue.toInt()
|
||||
height = newRows * tileWidth
|
||||
layers.forEach { it.resize(newRows, columns) }
|
||||
}
|
||||
|
||||
columnsProperty.addListener { _, _, newValue ->
|
||||
val newColumns = newValue.toInt()
|
||||
width = newColumns * tileWidth
|
||||
layers.forEach { it.resize(rows, newColumns) }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val INITIAL_ROWS = 20
|
||||
private const val INITIAL_COLUMNS = 20
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.model.map
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||
import javafx.beans.property.SimpleDoubleProperty
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.getValue
|
||||
import tornadofx.observableListOf
|
||||
import tornadofx.setValue
|
||||
|
||||
|
||||
class GameMap(val tileSet: TileSet) {
|
||||
val layers = observableListOf<Layer>()
|
||||
|
||||
val nameProperty = SimpleStringProperty()
|
||||
var name by nameProperty
|
||||
|
||||
val tileWidth = tileSet.tileWidth.toDouble()
|
||||
val tileHeight = tileSet.tileHeight.toDouble()
|
||||
|
||||
val rowsProperty = SimpleIntegerProperty(INITIAL_ROWS)
|
||||
var rows by rowsProperty
|
||||
|
||||
val columnsProperty = SimpleIntegerProperty(INITIAL_COLUMNS)
|
||||
var columns by columnsProperty
|
||||
|
||||
val widthProperty = SimpleDoubleProperty(INITIAL_COLUMNS * tileWidth)
|
||||
var width by widthProperty
|
||||
private set
|
||||
|
||||
val heightProperty = SimpleDoubleProperty(INITIAL_ROWS * tileHeight)
|
||||
var height by heightProperty
|
||||
private set
|
||||
|
||||
init {
|
||||
rowsProperty.addListener { _, _, newValue ->
|
||||
val newRows = newValue.toInt()
|
||||
height = newRows * tileWidth
|
||||
layers.forEach { it.resize(newRows, columns) }
|
||||
}
|
||||
|
||||
columnsProperty.addListener { _, _, newValue ->
|
||||
val newColumns = newValue.toInt()
|
||||
width = newColumns * tileWidth
|
||||
layers.forEach { it.resize(rows, newColumns) }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val INITIAL_ROWS = 20
|
||||
private const val INITIAL_COLUMNS = 20
|
||||
}
|
||||
}
|
||||
|
||||
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt
Executable file → Normal file
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
package com.bartlomiejpluta.base.editor.map.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.common.serial.Deserializer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
|
||||
package com.bartlomiejpluta.base.editor.map.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.common.serial.Deserializer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
|
||||
interface MapDeserializer : Deserializer<GameMap>
|
||||
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapSerializer.kt
Executable file → Normal file
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapSerializer.kt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
package com.bartlomiejpluta.base.editor.map.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.common.serial.Serializer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
|
||||
package com.bartlomiejpluta.base.editor.map.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.common.serial.Serializer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
|
||||
interface MapSerializer : Serializer<GameMap>
|
||||
102
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt
Executable file → Normal file
102
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt
Executable file → Normal file
@@ -1,52 +1,52 @@
|
||||
package com.bartlomiejpluta.base.editor.map.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||
import com.bartlomiejpluta.base.proto.GameMapProto
|
||||
import org.springframework.stereotype.Component
|
||||
import tornadofx.ResourceLookup
|
||||
import java.io.InputStream
|
||||
|
||||
@Component
|
||||
class ProtobufMapDeserializer : MapDeserializer {
|
||||
private val resources = ResourceLookup(this)
|
||||
private val tileset = TileSet(resources.image("/textures/tileset.png"), 160, 8)
|
||||
|
||||
override fun deserialize(input: InputStream): GameMap {
|
||||
val map = GameMap(tileset)
|
||||
val proto = GameMapProto.GameMap.parseFrom(input)
|
||||
map.name = proto.name
|
||||
map.rows = proto.rows
|
||||
map.columns = proto.columns
|
||||
|
||||
proto.layersList.forEach {
|
||||
map.layers.add(deserializeLayer(map.rows, map.columns, tileset, it))
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
||||
|
||||
private fun deserializeLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer {
|
||||
return when {
|
||||
proto.hasTileLayer() -> deserializeTileLayer(rows, columns, tileSet, proto)
|
||||
|
||||
else -> throw IllegalStateException("Not supported layer type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeTileLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer {
|
||||
val layer: Array<Array<Tile?>> = Array(rows) { Array(columns) { null } }
|
||||
|
||||
proto.tileLayer.tilesList.forEachIndexed { index, tile ->
|
||||
layer[index / columns][index % columns] = when(tile) {
|
||||
0 -> null
|
||||
else -> tileSet.getTile(tile-1)
|
||||
}
|
||||
}
|
||||
|
||||
return TileLayer(proto.name, rows, columns, layer)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||
import com.bartlomiejpluta.base.proto.GameMapProto
|
||||
import org.springframework.stereotype.Component
|
||||
import tornadofx.ResourceLookup
|
||||
import java.io.InputStream
|
||||
|
||||
@Component
|
||||
class ProtobufMapDeserializer : MapDeserializer {
|
||||
private val resources = ResourceLookup(this)
|
||||
private val tileset = TileSet(resources.image("/textures/tileset.png"), 160, 8)
|
||||
|
||||
override fun deserialize(input: InputStream): GameMap {
|
||||
val map = GameMap(tileset)
|
||||
val proto = GameMapProto.GameMap.parseFrom(input)
|
||||
map.name = proto.name
|
||||
map.rows = proto.rows
|
||||
map.columns = proto.columns
|
||||
|
||||
proto.layersList.forEach {
|
||||
map.layers.add(deserializeLayer(map.rows, map.columns, tileset, it))
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
||||
|
||||
private fun deserializeLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer {
|
||||
return when {
|
||||
proto.hasTileLayer() -> deserializeTileLayer(rows, columns, tileSet, proto)
|
||||
|
||||
else -> throw IllegalStateException("Not supported layer type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeTileLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer {
|
||||
val layer: Array<Array<Tile?>> = Array(rows) { Array(columns) { null } }
|
||||
|
||||
proto.tileLayer.tilesList.forEachIndexed { index, tile ->
|
||||
layer[index / columns][index % columns] = when(tile) {
|
||||
0 -> null
|
||||
else -> tileSet.getTile(tile-1)
|
||||
}
|
||||
}
|
||||
|
||||
return TileLayer(proto.name, rows, columns, layer)
|
||||
}
|
||||
}
|
||||
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt
Executable file → Normal file
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt
Executable file → Normal file
@@ -1,34 +1,34 @@
|
||||
package com.bartlomiejpluta.base.editor.map.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.proto.GameMapProto
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.OutputStream
|
||||
|
||||
@Component
|
||||
class ProtobufMapSerializer : MapSerializer {
|
||||
|
||||
override fun serialize(item: GameMap, output: OutputStream) {
|
||||
val protoMap = GameMapProto.GameMap.newBuilder()
|
||||
protoMap.name = item.name
|
||||
protoMap.rows = item.rows
|
||||
protoMap.columns = item.columns
|
||||
|
||||
item.layers.forEach { layer -> protoMap.addLayers(serializeLayer(layer)) }
|
||||
|
||||
protoMap.build().writeTo(output)
|
||||
}
|
||||
|
||||
private fun serializeLayer(layer: Layer): GameMapProto.Layer {
|
||||
return when (layer) {
|
||||
is TileLayer -> layer.layer.flatMap { it.asIterable() }
|
||||
.fold(GameMapProto.TileLayer.newBuilder()) { acc, tile -> acc.addTiles((tile?.id?.plus(1)) ?: 0) }
|
||||
.build()
|
||||
.let { GameMapProto.Layer.newBuilder().setName(layer.name).setTileLayer(it).build() }
|
||||
|
||||
else -> throw IllegalStateException("Not supported layer type")
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.proto.GameMapProto
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.OutputStream
|
||||
|
||||
@Component
|
||||
class ProtobufMapSerializer : MapSerializer {
|
||||
|
||||
override fun serialize(item: GameMap, output: OutputStream) {
|
||||
val protoMap = GameMapProto.GameMap.newBuilder()
|
||||
protoMap.name = item.name
|
||||
protoMap.rows = item.rows
|
||||
protoMap.columns = item.columns
|
||||
|
||||
item.layers.forEach { layer -> protoMap.addLayers(serializeLayer(layer)) }
|
||||
|
||||
protoMap.build().writeTo(output)
|
||||
}
|
||||
|
||||
private fun serializeLayer(layer: Layer): GameMapProto.Layer {
|
||||
return when (layer) {
|
||||
is TileLayer -> layer.layer.flatMap { it.asIterable() }
|
||||
.fold(GameMapProto.TileLayer.newBuilder()) { acc, tile -> acc.addTiles((tile?.id?.plus(1)) ?: 0) }
|
||||
.build()
|
||||
.let { GameMapProto.Layer.newBuilder().setName(layer.name).setTileLayer(it).build() }
|
||||
|
||||
else -> throw IllegalStateException("Not supported layer type")
|
||||
}
|
||||
}
|
||||
}
|
||||
72
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapFragment.kt
Executable file → Normal file
72
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapFragment.kt
Executable file → Normal file
@@ -1,36 +1,36 @@
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.tileset.view.TileSetView
|
||||
import tornadofx.*
|
||||
|
||||
|
||||
class MapFragment : Fragment() {
|
||||
override val scope = super.scope as UndoableScope
|
||||
|
||||
private val mapView = find<MapView>()
|
||||
private val layersView = find<MapLayersView>()
|
||||
private val tileSetView = find<TileSetView>()
|
||||
private val toolbarView = find<MapToolbarView>()
|
||||
private val statusBarView = find<MapStatusBarView>()
|
||||
|
||||
override val root = borderpane {
|
||||
top = toolbarView.root
|
||||
|
||||
center = mapView.root
|
||||
|
||||
right = drawer(multiselect = true) {
|
||||
item("Layers", expanded = true) {
|
||||
this += layersView.root
|
||||
}
|
||||
|
||||
item("Tile Set", expanded = true) {
|
||||
this += tileSetView.root.apply {
|
||||
maxHeightProperty().bind(this@item.heightProperty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bottom = statusBarView.root
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.tileset.view.TileSetView
|
||||
import tornadofx.*
|
||||
|
||||
|
||||
class MapFragment : Fragment() {
|
||||
override val scope = super.scope as UndoableScope
|
||||
|
||||
private val mapView = find<MapView>()
|
||||
private val layersView = find<MapLayersView>()
|
||||
private val tileSetView = find<TileSetView>()
|
||||
private val toolbarView = find<MapToolbarView>()
|
||||
private val statusBarView = find<MapStatusBarView>()
|
||||
|
||||
override val root = borderpane {
|
||||
top = toolbarView.root
|
||||
|
||||
center = mapView.root
|
||||
|
||||
right = drawer(multiselect = true) {
|
||||
item("Layers", expanded = true) {
|
||||
this += layersView.root
|
||||
}
|
||||
|
||||
item("Tile Set", expanded = true) {
|
||||
this += tileSetView.root.apply {
|
||||
maxHeightProperty().bind(this@item.heightProperty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bottom = statusBarView.root
|
||||
}
|
||||
}
|
||||
|
||||
188
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapLayersView.kt
Executable file → Normal file
188
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapLayersView.kt
Executable file → Normal file
@@ -1,95 +1,95 @@
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.command.model.map.CreateLayerCommand
|
||||
import com.bartlomiejpluta.base.editor.command.model.map.MoveLayerCommand
|
||||
import com.bartlomiejpluta.base.editor.command.model.map.RemoveLayerCommand
|
||||
import com.bartlomiejpluta.base.editor.command.model.map.RenameLayerCommand
|
||||
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
|
||||
import com.bartlomiejpluta.base.editor.event.RedrawMapRequestEvent
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.control.TableView
|
||||
import org.kordamp.ikonli.javafx.FontIcon
|
||||
import tornadofx.*
|
||||
|
||||
class MapLayersView : View() {
|
||||
private val undoRedoService: UndoRedoService by di()
|
||||
|
||||
override val scope = super.scope as UndoableScope
|
||||
|
||||
private val mapVM = find<GameMapVM>()
|
||||
|
||||
private val editorStateVM = find<EditorStateVM>()
|
||||
|
||||
private var layersPane = TableView(mapVM.layers).apply {
|
||||
column("Layer Name", Layer::nameProperty).makeEditable().setOnEditCommit {
|
||||
val command = RenameLayerCommand(it.rowValue, it.newValue)
|
||||
command.execute()
|
||||
undoRedoService.push(command, scope)
|
||||
}
|
||||
|
||||
editorStateVM.selectedLayerProperty.bind(selectionModel.selectedIndexProperty())
|
||||
}
|
||||
|
||||
override val root = borderpane {
|
||||
center = layersPane
|
||||
|
||||
bottom = toolbar {
|
||||
button(graphic = FontIcon("fa-plus")) {
|
||||
action {
|
||||
val tileLayer = TileLayer("Layer ${mapVM.layers.size + 1}", mapVM.rows, mapVM.columns)
|
||||
val command = CreateLayerCommand(mapVM.item, tileLayer)
|
||||
command.execute()
|
||||
layersPane.selectionModel.select(mapVM.layers.size - 1)
|
||||
undoRedoService.push(command, scope)
|
||||
}
|
||||
}
|
||||
|
||||
button(graphic = FontIcon("fa-chevron-up")) {
|
||||
enableWhen(editorStateVM.selectedLayerProperty.greaterThan(0))
|
||||
action {
|
||||
val newIndex = editorStateVM.selectedLayer - 1
|
||||
val command = MoveLayerCommand(mapVM.item, editorStateVM.selectedLayer, newIndex)
|
||||
command.execute()
|
||||
layersPane.selectionModel.select(newIndex)
|
||||
fire(RedrawMapRequestEvent)
|
||||
undoRedoService.push(command, scope)
|
||||
}
|
||||
}
|
||||
|
||||
button(graphic = FontIcon("fa-chevron-down")) {
|
||||
enableWhen(
|
||||
editorStateVM.selectedLayerProperty.lessThan(mapVM.layers.sizeProperty().minus(1))
|
||||
.and(editorStateVM.selectedLayerProperty.greaterThanOrEqualTo(0))
|
||||
)
|
||||
action {
|
||||
val newIndex = editorStateVM.selectedLayer + 1
|
||||
val command = MoveLayerCommand(mapVM.item, editorStateVM.selectedLayer, newIndex)
|
||||
command.execute()
|
||||
layersPane.selectionModel.select(newIndex)
|
||||
fire(RedrawMapRequestEvent)
|
||||
undoRedoService.push(command, scope)
|
||||
}
|
||||
}
|
||||
|
||||
button(graphic = FontIcon("fa-trash")) {
|
||||
enableWhen(editorStateVM.selectedLayerProperty.greaterThanOrEqualTo(0))
|
||||
action {
|
||||
var index = editorStateVM.selectedLayer
|
||||
val command = RemoveLayerCommand(mapVM.item, index)
|
||||
command.execute()
|
||||
|
||||
if (--index >= 0) {
|
||||
layersPane.selectionModel.select(index)
|
||||
}
|
||||
|
||||
fire(RedrawMapRequestEvent)
|
||||
undoRedoService.push(command, scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.command.model.map.CreateLayerCommand
|
||||
import com.bartlomiejpluta.base.editor.command.model.map.MoveLayerCommand
|
||||
import com.bartlomiejpluta.base.editor.command.model.map.RemoveLayerCommand
|
||||
import com.bartlomiejpluta.base.editor.command.model.map.RenameLayerCommand
|
||||
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
|
||||
import com.bartlomiejpluta.base.editor.event.RedrawMapRequestEvent
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.control.TableView
|
||||
import org.kordamp.ikonli.javafx.FontIcon
|
||||
import tornadofx.*
|
||||
|
||||
class MapLayersView : View() {
|
||||
private val undoRedoService: UndoRedoService by di()
|
||||
|
||||
override val scope = super.scope as UndoableScope
|
||||
|
||||
private val mapVM = find<GameMapVM>()
|
||||
|
||||
private val editorStateVM = find<EditorStateVM>()
|
||||
|
||||
private var layersPane = TableView(mapVM.layers).apply {
|
||||
column("Layer Name", Layer::nameProperty).makeEditable().setOnEditCommit {
|
||||
val command = RenameLayerCommand(it.rowValue, it.newValue)
|
||||
command.execute()
|
||||
undoRedoService.push(command, scope)
|
||||
}
|
||||
|
||||
editorStateVM.selectedLayerProperty.bind(selectionModel.selectedIndexProperty())
|
||||
}
|
||||
|
||||
override val root = borderpane {
|
||||
center = layersPane
|
||||
|
||||
bottom = toolbar {
|
||||
button(graphic = FontIcon("fa-plus")) {
|
||||
action {
|
||||
val tileLayer = TileLayer("Layer ${mapVM.layers.size + 1}", mapVM.rows, mapVM.columns)
|
||||
val command = CreateLayerCommand(mapVM.item, tileLayer)
|
||||
command.execute()
|
||||
layersPane.selectionModel.select(mapVM.layers.size - 1)
|
||||
undoRedoService.push(command, scope)
|
||||
}
|
||||
}
|
||||
|
||||
button(graphic = FontIcon("fa-chevron-up")) {
|
||||
enableWhen(editorStateVM.selectedLayerProperty.greaterThan(0))
|
||||
action {
|
||||
val newIndex = editorStateVM.selectedLayer - 1
|
||||
val command = MoveLayerCommand(mapVM.item, editorStateVM.selectedLayer, newIndex)
|
||||
command.execute()
|
||||
layersPane.selectionModel.select(newIndex)
|
||||
fire(RedrawMapRequestEvent)
|
||||
undoRedoService.push(command, scope)
|
||||
}
|
||||
}
|
||||
|
||||
button(graphic = FontIcon("fa-chevron-down")) {
|
||||
enableWhen(
|
||||
editorStateVM.selectedLayerProperty.lessThan(mapVM.layers.sizeProperty().minus(1))
|
||||
.and(editorStateVM.selectedLayerProperty.greaterThanOrEqualTo(0))
|
||||
)
|
||||
action {
|
||||
val newIndex = editorStateVM.selectedLayer + 1
|
||||
val command = MoveLayerCommand(mapVM.item, editorStateVM.selectedLayer, newIndex)
|
||||
command.execute()
|
||||
layersPane.selectionModel.select(newIndex)
|
||||
fire(RedrawMapRequestEvent)
|
||||
undoRedoService.push(command, scope)
|
||||
}
|
||||
}
|
||||
|
||||
button(graphic = FontIcon("fa-trash")) {
|
||||
enableWhen(editorStateVM.selectedLayerProperty.greaterThanOrEqualTo(0))
|
||||
action {
|
||||
var index = editorStateVM.selectedLayer
|
||||
val command = RemoveLayerCommand(mapVM.item, index)
|
||||
command.execute()
|
||||
|
||||
if (--index >= 0) {
|
||||
layersPane.selectionModel.select(index)
|
||||
}
|
||||
|
||||
fire(RedrawMapRequestEvent)
|
||||
undoRedoService.push(command, scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
164
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapSettingsFragment.kt
Executable file → Normal file
164
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapSettingsFragment.kt
Executable file → Normal file
@@ -1,83 +1,83 @@
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import org.kordamp.ikonli.javafx.FontIcon
|
||||
import tornadofx.*
|
||||
|
||||
class MapSettingsFragment : Fragment("Map Settings") {
|
||||
override val scope = super.scope as UndoableScope
|
||||
private val undoRedoService: UndoRedoService by di()
|
||||
|
||||
private val mapVM = find<GameMapVM>()
|
||||
|
||||
var result = false
|
||||
private set
|
||||
|
||||
override val root = form {
|
||||
icon = FontIcon("fa-map-o")
|
||||
|
||||
fieldset("Map Settings") {
|
||||
field("Map name") {
|
||||
textfield(mapVM.nameProperty) {
|
||||
required()
|
||||
whenDocked { requestFocus() }
|
||||
}
|
||||
}
|
||||
|
||||
field("Rows") {
|
||||
|
||||
textfield(mapVM.rowsProperty) {
|
||||
stripNonInteger()
|
||||
required()
|
||||
validator {
|
||||
when (it?.toIntOrNull()) {
|
||||
in 1..50 -> null
|
||||
in 50..100 -> warning("The map sizes over 50 can impact game performance")
|
||||
else -> error("The map size must be between 1 and 100")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
field("Columns") {
|
||||
textfield(mapVM.columnsProperty) {
|
||||
stripNonInteger()
|
||||
required()
|
||||
validator {
|
||||
when (it?.toIntOrNull()) {
|
||||
in 1..50 -> null
|
||||
in 50..100 -> warning("The map sizes over 50 can impact game performance")
|
||||
else -> error("The map size must be between 1 and 100")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label("Warning: Submitting the form will clear related undo/redo stacks!")
|
||||
}
|
||||
|
||||
buttonbar {
|
||||
button("Ok") {
|
||||
shortcut("Enter")
|
||||
|
||||
action {
|
||||
mapVM.commit {
|
||||
result = true
|
||||
undoRedoService.clear(scope)
|
||||
close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button("Reset") {
|
||||
action { mapVM.rollback() }
|
||||
}
|
||||
|
||||
button("Cancel") {
|
||||
action { close() }
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import org.kordamp.ikonli.javafx.FontIcon
|
||||
import tornadofx.*
|
||||
|
||||
class MapSettingsFragment : Fragment("Map Settings") {
|
||||
override val scope = super.scope as UndoableScope
|
||||
private val undoRedoService: UndoRedoService by di()
|
||||
|
||||
private val mapVM = find<GameMapVM>()
|
||||
|
||||
var result = false
|
||||
private set
|
||||
|
||||
override val root = form {
|
||||
icon = FontIcon("fa-map-o")
|
||||
|
||||
fieldset("Map Settings") {
|
||||
field("Map name") {
|
||||
textfield(mapVM.nameProperty) {
|
||||
required()
|
||||
whenDocked { requestFocus() }
|
||||
}
|
||||
}
|
||||
|
||||
field("Rows") {
|
||||
|
||||
textfield(mapVM.rowsProperty) {
|
||||
stripNonInteger()
|
||||
required()
|
||||
validator {
|
||||
when (it?.toIntOrNull()) {
|
||||
in 1..50 -> null
|
||||
in 50..100 -> warning("The map sizes over 50 can impact game performance")
|
||||
else -> error("The map size must be between 1 and 100")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
field("Columns") {
|
||||
textfield(mapVM.columnsProperty) {
|
||||
stripNonInteger()
|
||||
required()
|
||||
validator {
|
||||
when (it?.toIntOrNull()) {
|
||||
in 1..50 -> null
|
||||
in 50..100 -> warning("The map sizes over 50 can impact game performance")
|
||||
else -> error("The map size must be between 1 and 100")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label("Warning: Submitting the form will clear related undo/redo stacks!")
|
||||
}
|
||||
|
||||
buttonbar {
|
||||
button("Ok") {
|
||||
shortcut("Enter")
|
||||
|
||||
action {
|
||||
mapVM.commit {
|
||||
result = true
|
||||
undoRedoService.clear(scope)
|
||||
close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button("Reset") {
|
||||
action { mapVM.rollback() }
|
||||
}
|
||||
|
||||
button("Cancel") {
|
||||
action { close() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapStatusBarView.kt
Executable file → Normal file
66
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapStatusBarView.kt
Executable file → Normal file
@@ -1,34 +1,34 @@
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import javafx.beans.binding.Bindings
|
||||
import org.kordamp.ikonli.javafx.FontIcon
|
||||
import tornadofx.*
|
||||
|
||||
class MapStatusBarView : View() {
|
||||
|
||||
private val editorStateVM = find<EditorStateVM>()
|
||||
|
||||
override val root = hbox {
|
||||
spacing = 50.0
|
||||
paddingAll = 5.0
|
||||
|
||||
hbox {
|
||||
this += FontIcon("fa-search-minus")
|
||||
|
||||
slider(0.5..5.0) {
|
||||
bind(editorStateVM.zoomProperty)
|
||||
}
|
||||
|
||||
this += FontIcon("fa-search-plus")
|
||||
}
|
||||
|
||||
label(
|
||||
Bindings.format(
|
||||
"Cursor: %d, %d",
|
||||
editorStateVM.cursorColumnProperty.add(1),
|
||||
editorStateVM.cursorRowProperty.add(1)
|
||||
)
|
||||
)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import javafx.beans.binding.Bindings
|
||||
import org.kordamp.ikonli.javafx.FontIcon
|
||||
import tornadofx.*
|
||||
|
||||
class MapStatusBarView : View() {
|
||||
|
||||
private val editorStateVM = find<EditorStateVM>()
|
||||
|
||||
override val root = hbox {
|
||||
spacing = 50.0
|
||||
paddingAll = 5.0
|
||||
|
||||
hbox {
|
||||
this += FontIcon("fa-search-minus")
|
||||
|
||||
slider(0.5..5.0) {
|
||||
bind(editorStateVM.zoomProperty)
|
||||
}
|
||||
|
||||
this += FontIcon("fa-search-plus")
|
||||
}
|
||||
|
||||
label(
|
||||
Bindings.format(
|
||||
"Cursor: %d, %d",
|
||||
editorStateVM.cursorColumnProperty.add(1),
|
||||
editorStateVM.cursorRowProperty.add(1)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
208
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapToolbarView.kt
Executable file → Normal file
208
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapToolbarView.kt
Executable file → Normal file
@@ -1,105 +1,105 @@
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
|
||||
import com.bartlomiejpluta.base.editor.event.RedrawMapRequestEvent
|
||||
import com.bartlomiejpluta.base.editor.map.model.brush.BrushMode
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.control.ToggleGroup
|
||||
import org.kordamp.ikonli.javafx.FontIcon
|
||||
import tornadofx.*
|
||||
|
||||
class MapToolbarView : View() {
|
||||
private val undoRedoService: UndoRedoService by di()
|
||||
|
||||
override val scope = super.scope as UndoableScope
|
||||
|
||||
private val mapVM = find<GameMapVM>()
|
||||
private val brushVM = find<BrushVM>()
|
||||
private val editorStateVM = find<EditorStateVM>()
|
||||
|
||||
private val brushMode = ToggleGroup().apply {
|
||||
brushVM.itemProperty.addListener { _, _, brush ->
|
||||
selectedValueProperty<BrushMode>().value = brush.mode
|
||||
}
|
||||
}
|
||||
|
||||
override val root = toolbar {
|
||||
button(graphic = FontIcon("fa-undo")) {
|
||||
shortcut("Ctrl+Z")
|
||||
action {
|
||||
undoRedoService.undo(scope)
|
||||
fire(RedrawMapRequestEvent)
|
||||
}
|
||||
}
|
||||
|
||||
button(graphic = FontIcon("fa-repeat")) {
|
||||
shortcut("Ctrl+Shift+Z")
|
||||
action {
|
||||
undoRedoService.redo(scope)
|
||||
fire(RedrawMapRequestEvent)
|
||||
}
|
||||
}
|
||||
|
||||
togglebutton {
|
||||
graphic = FontIcon("fa-window-restore")
|
||||
|
||||
action {
|
||||
editorStateVM.coverUnderlyingLayers = isSelected
|
||||
}
|
||||
}
|
||||
|
||||
togglebutton {
|
||||
graphic = FontIcon("fa-th")
|
||||
|
||||
action {
|
||||
editorStateVM.showGrid = isSelected
|
||||
}
|
||||
}
|
||||
|
||||
togglebutton(value = BrushMode.PAINTING_MODE, group = brushMode) {
|
||||
graphic = FontIcon("fa-paint-brush")
|
||||
|
||||
action {
|
||||
brushVM.item = brushVM.withMode(BrushMode.PAINTING_MODE)
|
||||
brushVM.commit()
|
||||
}
|
||||
}
|
||||
|
||||
togglebutton(value = BrushMode.ERASING_MODE, group = brushMode) {
|
||||
graphic = FontIcon("fa-eraser")
|
||||
|
||||
action {
|
||||
brushVM.item = brushVM.withMode(BrushMode.ERASING_MODE)
|
||||
brushVM.commit()
|
||||
}
|
||||
}
|
||||
|
||||
this += FontIcon("fa-paint-brush").apply { iconSize = 10 }
|
||||
|
||||
slider(1..5) {
|
||||
majorTickUnit = 1.0
|
||||
isSnapToTicks = true
|
||||
minorTickCount = 0
|
||||
|
||||
valueProperty().addListener { _, _, newValue ->
|
||||
brushVM.item = brushVM.withRange(newValue.toInt())
|
||||
brushVM.commit()
|
||||
}
|
||||
|
||||
brushVM.itemProperty.addListener { _, _, brush ->
|
||||
value = brush.range.toDouble()
|
||||
}
|
||||
}
|
||||
|
||||
this += FontIcon("fa-paint-brush").apply { iconSize = 15 }
|
||||
|
||||
button(graphic = FontIcon("fa-sliders")) {
|
||||
action {
|
||||
find<MapSettingsFragment>().openModal(block = true, resizable = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
|
||||
import com.bartlomiejpluta.base.editor.event.RedrawMapRequestEvent
|
||||
import com.bartlomiejpluta.base.editor.map.model.brush.BrushMode
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.control.ToggleGroup
|
||||
import org.kordamp.ikonli.javafx.FontIcon
|
||||
import tornadofx.*
|
||||
|
||||
class MapToolbarView : View() {
|
||||
private val undoRedoService: UndoRedoService by di()
|
||||
|
||||
override val scope = super.scope as UndoableScope
|
||||
|
||||
private val mapVM = find<GameMapVM>()
|
||||
private val brushVM = find<BrushVM>()
|
||||
private val editorStateVM = find<EditorStateVM>()
|
||||
|
||||
private val brushMode = ToggleGroup().apply {
|
||||
brushVM.itemProperty.addListener { _, _, brush ->
|
||||
selectedValueProperty<BrushMode>().value = brush.mode
|
||||
}
|
||||
}
|
||||
|
||||
override val root = toolbar {
|
||||
button(graphic = FontIcon("fa-undo")) {
|
||||
shortcut("Ctrl+Z")
|
||||
action {
|
||||
undoRedoService.undo(scope)
|
||||
fire(RedrawMapRequestEvent)
|
||||
}
|
||||
}
|
||||
|
||||
button(graphic = FontIcon("fa-repeat")) {
|
||||
shortcut("Ctrl+Shift+Z")
|
||||
action {
|
||||
undoRedoService.redo(scope)
|
||||
fire(RedrawMapRequestEvent)
|
||||
}
|
||||
}
|
||||
|
||||
togglebutton {
|
||||
graphic = FontIcon("fa-window-restore")
|
||||
|
||||
action {
|
||||
editorStateVM.coverUnderlyingLayers = isSelected
|
||||
}
|
||||
}
|
||||
|
||||
togglebutton {
|
||||
graphic = FontIcon("fa-th")
|
||||
|
||||
action {
|
||||
editorStateVM.showGrid = isSelected
|
||||
}
|
||||
}
|
||||
|
||||
togglebutton(value = BrushMode.PAINTING_MODE, group = brushMode) {
|
||||
graphic = FontIcon("fa-paint-brush")
|
||||
|
||||
action {
|
||||
brushVM.item = brushVM.withMode(BrushMode.PAINTING_MODE)
|
||||
brushVM.commit()
|
||||
}
|
||||
}
|
||||
|
||||
togglebutton(value = BrushMode.ERASING_MODE, group = brushMode) {
|
||||
graphic = FontIcon("fa-eraser")
|
||||
|
||||
action {
|
||||
brushVM.item = brushVM.withMode(BrushMode.ERASING_MODE)
|
||||
brushVM.commit()
|
||||
}
|
||||
}
|
||||
|
||||
this += FontIcon("fa-paint-brush").apply { iconSize = 10 }
|
||||
|
||||
slider(1..5) {
|
||||
majorTickUnit = 1.0
|
||||
isSnapToTicks = true
|
||||
minorTickCount = 0
|
||||
|
||||
valueProperty().addListener { _, _, newValue ->
|
||||
brushVM.item = brushVM.withRange(newValue.toInt())
|
||||
brushVM.commit()
|
||||
}
|
||||
|
||||
brushVM.itemProperty.addListener { _, _, brush ->
|
||||
value = brush.range.toDouble()
|
||||
}
|
||||
}
|
||||
|
||||
this += FontIcon("fa-paint-brush").apply { iconSize = 15 }
|
||||
|
||||
button(graphic = FontIcon("fa-sliders")) {
|
||||
action {
|
||||
find<MapSettingsFragment>().openModal(block = true, resizable = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapView.kt
Executable file → Normal file
126
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/MapView.kt
Executable file → Normal file
@@ -1,64 +1,64 @@
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
|
||||
import com.bartlomiejpluta.base.editor.event.RedrawMapRequestEvent
|
||||
import com.bartlomiejpluta.base.editor.map.component.MapPane
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.input.MouseButton
|
||||
import javafx.scene.input.MouseEvent
|
||||
import javafx.scene.transform.Scale
|
||||
import tornadofx.View
|
||||
import tornadofx.group
|
||||
import tornadofx.plusAssign
|
||||
import tornadofx.scrollpane
|
||||
|
||||
|
||||
class MapView : View() {
|
||||
private val undoRedoService: UndoRedoService by di()
|
||||
|
||||
override val scope = super.scope as UndoableScope
|
||||
|
||||
private val mapVM = find<GameMapVM>()
|
||||
|
||||
private val brushVM = find<BrushVM>()
|
||||
|
||||
private val editorStateVM = find<EditorStateVM>()
|
||||
|
||||
private val mapPane = MapPane(mapVM, brushVM, editorStateVM) { undoRedoService.push(it, scope) }
|
||||
|
||||
private val zoom = Scale(1.0, 1.0, 0.0, 0.0).apply {
|
||||
xProperty().bind(editorStateVM.zoomProperty)
|
||||
yProperty().bind(editorStateVM.zoomProperty)
|
||||
}
|
||||
|
||||
init {
|
||||
brushVM.item = mapVM.tileSet.baseBrush
|
||||
brushVM.commit()
|
||||
|
||||
subscribe<RedrawMapRequestEvent> { mapPane.render() }
|
||||
}
|
||||
|
||||
override val root = scrollpane {
|
||||
prefWidth = 640.0
|
||||
prefHeight = 480.0
|
||||
isPannable = true
|
||||
|
||||
group {
|
||||
|
||||
// Let the ScrollPane.viewRect only pan on middle button.
|
||||
addEventHandler(MouseEvent.ANY) {
|
||||
if (it.button != MouseButton.MIDDLE) {
|
||||
it.consume()
|
||||
}
|
||||
}
|
||||
|
||||
group {
|
||||
this += mapPane
|
||||
transforms += zoom
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.map.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.command.context.UndoableScope
|
||||
import com.bartlomiejpluta.base.editor.command.service.UndoRedoService
|
||||
import com.bartlomiejpluta.base.editor.event.RedrawMapRequestEvent
|
||||
import com.bartlomiejpluta.base.editor.map.component.MapPane
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.input.MouseButton
|
||||
import javafx.scene.input.MouseEvent
|
||||
import javafx.scene.transform.Scale
|
||||
import tornadofx.View
|
||||
import tornadofx.group
|
||||
import tornadofx.plusAssign
|
||||
import tornadofx.scrollpane
|
||||
|
||||
|
||||
class MapView : View() {
|
||||
private val undoRedoService: UndoRedoService by di()
|
||||
|
||||
override val scope = super.scope as UndoableScope
|
||||
|
||||
private val mapVM = find<GameMapVM>()
|
||||
|
||||
private val brushVM = find<BrushVM>()
|
||||
|
||||
private val editorStateVM = find<EditorStateVM>()
|
||||
|
||||
private val mapPane = MapPane(mapVM, brushVM, editorStateVM) { undoRedoService.push(it, scope) }
|
||||
|
||||
private val zoom = Scale(1.0, 1.0, 0.0, 0.0).apply {
|
||||
xProperty().bind(editorStateVM.zoomProperty)
|
||||
yProperty().bind(editorStateVM.zoomProperty)
|
||||
}
|
||||
|
||||
init {
|
||||
brushVM.item = mapVM.tileSet.baseBrush
|
||||
brushVM.commit()
|
||||
|
||||
subscribe<RedrawMapRequestEvent> { mapPane.render() }
|
||||
}
|
||||
|
||||
override val root = scrollpane {
|
||||
prefWidth = 640.0
|
||||
prefHeight = 480.0
|
||||
isPannable = true
|
||||
|
||||
group {
|
||||
|
||||
// Let the ScrollPane.viewRect only pan on middle button.
|
||||
addEventHandler(MouseEvent.ANY) {
|
||||
if (it.button != MouseButton.MIDDLE) {
|
||||
it.consume()
|
||||
}
|
||||
}
|
||||
|
||||
group {
|
||||
this += mapPane
|
||||
transforms += zoom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/BrushVM.kt
Executable file → Normal file
56
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/BrushVM.kt
Executable file → Normal file
@@ -1,29 +1,29 @@
|
||||
package com.bartlomiejpluta.base.editor.map.viewmodel
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
||||
import com.bartlomiejpluta.base.editor.map.model.brush.BrushMode
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import tornadofx.ItemViewModel
|
||||
import tornadofx.getValue
|
||||
|
||||
class BrushVM : ItemViewModel<Brush>(Brush.of(arrayOf(arrayOf()))) {
|
||||
val brush = bind(Brush::brush)
|
||||
|
||||
val rowsProperty = bind(Brush::rowsProperty)
|
||||
val rows by rowsProperty
|
||||
|
||||
val columnsProperty = bind(Brush::columnsProperty)
|
||||
val columns by columnsProperty
|
||||
|
||||
val rangeProperty = bind(Brush::rangeProperty)
|
||||
val range by rangeProperty
|
||||
|
||||
val modeProperty = bind(Brush::modeProperty)
|
||||
val mode by modeProperty
|
||||
|
||||
fun forEach(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) = item.forEach(consumer)
|
||||
|
||||
fun withRange(range: Int) = item.withRange(range)
|
||||
|
||||
fun withMode(mode: BrushMode) = item.withMode(mode)
|
||||
package com.bartlomiejpluta.base.editor.map.viewmodel
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
||||
import com.bartlomiejpluta.base.editor.map.model.brush.BrushMode
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.Tile
|
||||
import tornadofx.ItemViewModel
|
||||
import tornadofx.getValue
|
||||
|
||||
class BrushVM : ItemViewModel<Brush>(Brush.of(arrayOf(arrayOf()))) {
|
||||
val brush = bind(Brush::brush)
|
||||
|
||||
val rowsProperty = bind(Brush::rowsProperty)
|
||||
val rows by rowsProperty
|
||||
|
||||
val columnsProperty = bind(Brush::columnsProperty)
|
||||
val columns by columnsProperty
|
||||
|
||||
val rangeProperty = bind(Brush::rangeProperty)
|
||||
val range by rangeProperty
|
||||
|
||||
val modeProperty = bind(Brush::modeProperty)
|
||||
val mode by modeProperty
|
||||
|
||||
fun forEach(consumer: (row: Int, column: Int, centerRow: Int, centerColumn: Int, tile: Tile?) -> Unit) = item.forEach(consumer)
|
||||
|
||||
fun withRange(range: Int) = item.withRange(range)
|
||||
|
||||
fun withMode(mode: BrushMode) = item.withMode(mode)
|
||||
}
|
||||
54
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/EditorStateVM.kt
Executable file → Normal file
54
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/EditorStateVM.kt
Executable file → Normal file
@@ -1,28 +1,28 @@
|
||||
package com.bartlomiejpluta.base.editor.map.viewmodel
|
||||
|
||||
import javafx.beans.property.SimpleBooleanProperty
|
||||
import javafx.beans.property.SimpleDoubleProperty
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import tornadofx.ViewModel
|
||||
import tornadofx.getValue
|
||||
import tornadofx.setValue
|
||||
|
||||
class EditorStateVM : ViewModel() {
|
||||
val selectedLayerProperty = SimpleIntegerProperty(0)
|
||||
var selectedLayer by selectedLayerProperty
|
||||
|
||||
val showGridProperty = SimpleBooleanProperty(true)
|
||||
var showGrid by showGridProperty
|
||||
|
||||
val coverUnderlyingLayersProperty = SimpleBooleanProperty(true)
|
||||
var coverUnderlyingLayers by coverUnderlyingLayersProperty
|
||||
|
||||
val zoomProperty = SimpleDoubleProperty(1.0)
|
||||
var zoom by zoomProperty
|
||||
|
||||
val cursorRowProperty = SimpleIntegerProperty(-1)
|
||||
val cursorRow by cursorRowProperty
|
||||
|
||||
val cursorColumnProperty = SimpleIntegerProperty(-1)
|
||||
val cursorColumn by cursorColumnProperty
|
||||
package com.bartlomiejpluta.base.editor.map.viewmodel
|
||||
|
||||
import javafx.beans.property.SimpleBooleanProperty
|
||||
import javafx.beans.property.SimpleDoubleProperty
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import tornadofx.ViewModel
|
||||
import tornadofx.getValue
|
||||
import tornadofx.setValue
|
||||
|
||||
class EditorStateVM : ViewModel() {
|
||||
val selectedLayerProperty = SimpleIntegerProperty(0)
|
||||
var selectedLayer by selectedLayerProperty
|
||||
|
||||
val showGridProperty = SimpleBooleanProperty(true)
|
||||
var showGrid by showGridProperty
|
||||
|
||||
val coverUnderlyingLayersProperty = SimpleBooleanProperty(true)
|
||||
var coverUnderlyingLayers by coverUnderlyingLayersProperty
|
||||
|
||||
val zoomProperty = SimpleDoubleProperty(1.0)
|
||||
var zoom by zoomProperty
|
||||
|
||||
val cursorRowProperty = SimpleIntegerProperty(-1)
|
||||
val cursorRow by cursorRowProperty
|
||||
|
||||
val cursorColumnProperty = SimpleIntegerProperty(-1)
|
||||
val cursorColumn by cursorColumnProperty
|
||||
}
|
||||
78
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapVM.kt
Executable file → Normal file
78
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapVM.kt
Executable file → Normal file
@@ -1,39 +1,39 @@
|
||||
package com.bartlomiejpluta.base.editor.map.viewmodel
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import javafx.beans.property.SimpleListProperty
|
||||
import tornadofx.ItemViewModel
|
||||
import tornadofx.getValue
|
||||
import tornadofx.setValue
|
||||
|
||||
class GameMapVM(map: GameMap) : ItemViewModel<GameMap>(map) {
|
||||
val layers: SimpleListProperty<Layer> = bind(GameMap::layers)
|
||||
|
||||
val nameProperty = bind(GameMap::nameProperty)
|
||||
var name by nameProperty
|
||||
|
||||
val tileSetProperty = bind(GameMap::tileSet)
|
||||
val tileSet by tileSetProperty
|
||||
|
||||
val rowsProperty = bind(GameMap::rowsProperty)
|
||||
var rows by rowsProperty
|
||||
|
||||
val columnsProperty = bind(GameMap::columnsProperty)
|
||||
var columns by columnsProperty
|
||||
|
||||
val tileWidthProperty = bind(GameMap::tileWidth)
|
||||
val tileWidth by tileWidthProperty
|
||||
|
||||
val tileHeightProperty = bind(GameMap::tileHeight)
|
||||
val tileHeight by tileHeightProperty
|
||||
|
||||
val widthProperty = bind(GameMap::widthProperty)
|
||||
val width by widthProperty
|
||||
|
||||
val heightProperty = bind(GameMap::heightProperty)
|
||||
val height by heightProperty
|
||||
}
|
||||
|
||||
|
||||
|
||||
package com.bartlomiejpluta.base.editor.map.viewmodel
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.layer.Layer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import javafx.beans.property.SimpleListProperty
|
||||
import tornadofx.ItemViewModel
|
||||
import tornadofx.getValue
|
||||
import tornadofx.setValue
|
||||
|
||||
class GameMapVM(map: GameMap) : ItemViewModel<GameMap>(map) {
|
||||
val layers: SimpleListProperty<Layer> = bind(GameMap::layers)
|
||||
|
||||
val nameProperty = bind(GameMap::nameProperty)
|
||||
var name by nameProperty
|
||||
|
||||
val tileSetProperty = bind(GameMap::tileSet)
|
||||
val tileSet by tileSetProperty
|
||||
|
||||
val rowsProperty = bind(GameMap::rowsProperty)
|
||||
var rows by rowsProperty
|
||||
|
||||
val columnsProperty = bind(GameMap::columnsProperty)
|
||||
var columns by columnsProperty
|
||||
|
||||
val tileWidthProperty = bind(GameMap::tileWidth)
|
||||
val tileWidth by tileWidthProperty
|
||||
|
||||
val tileHeightProperty = bind(GameMap::tileHeight)
|
||||
val tileHeight by tileHeightProperty
|
||||
|
||||
val widthProperty = bind(GameMap::widthProperty)
|
||||
val width by widthProperty
|
||||
|
||||
val heightProperty = bind(GameMap::heightProperty)
|
||||
val height by heightProperty
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
62
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/manager/DefaultProjectManager.kt
Executable file → Normal file
62
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/manager/DefaultProjectManager.kt
Executable file → Normal file
@@ -1,32 +1,32 @@
|
||||
package com.bartlomiejpluta.base.editor.project.manager
|
||||
|
||||
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 org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
|
||||
@Component
|
||||
class DefaultProjectManager : ProjectManager {
|
||||
|
||||
@Autowired
|
||||
private lateinit var projectSerializer: ProjectSerializer
|
||||
|
||||
@Autowired
|
||||
private lateinit var projectDeserializer: ProjectDeserializer
|
||||
|
||||
override fun saveProject(project: Project) {
|
||||
project.sourceDirectory.mkdirs()
|
||||
|
||||
FileOutputStream(File(project.sourceDirectory, "project.bep")).use {
|
||||
projectSerializer.serialize(project, it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openProject(file: File) = FileInputStream(file)
|
||||
.use { projectDeserializer.deserialize(it) }
|
||||
.apply { sourceDirectoryProperty.value = file.parentFile }
|
||||
package com.bartlomiejpluta.base.editor.project.manager
|
||||
|
||||
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 org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
|
||||
@Component
|
||||
class DefaultProjectManager : ProjectManager {
|
||||
|
||||
@Autowired
|
||||
private lateinit var projectSerializer: ProjectSerializer
|
||||
|
||||
@Autowired
|
||||
private lateinit var projectDeserializer: ProjectDeserializer
|
||||
|
||||
override fun saveProject(project: Project) {
|
||||
project.sourceDirectory.mkdirs()
|
||||
|
||||
FileOutputStream(File(project.sourceDirectory, "project.bep")).use {
|
||||
projectSerializer.serialize(project, it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openProject(file: File) = FileInputStream(file)
|
||||
.use { projectDeserializer.deserialize(it) }
|
||||
.apply { sourceDirectoryProperty.value = file.parentFile }
|
||||
}
|
||||
16
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/manager/ProjectManager.kt
Executable file → Normal file
16
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/manager/ProjectManager.kt
Executable file → Normal file
@@ -1,9 +1,9 @@
|
||||
package com.bartlomiejpluta.base.editor.project.manager
|
||||
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import java.io.File
|
||||
|
||||
interface ProjectManager {
|
||||
fun saveProject(project: Project)
|
||||
fun openProject(file: File): Project
|
||||
package com.bartlomiejpluta.base.editor.project.manager
|
||||
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import java.io.File
|
||||
|
||||
interface ProjectManager {
|
||||
fun saveProject(project: Project)
|
||||
fun openProject(file: File): Project
|
||||
}
|
||||
28
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt
Executable file → Normal file
28
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/model/Project.kt
Executable file → Normal file
@@ -1,14 +1,14 @@
|
||||
package com.bartlomiejpluta.base.editor.project.model
|
||||
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.*
|
||||
import java.io.File
|
||||
|
||||
class Project {
|
||||
val nameProperty = SimpleStringProperty()
|
||||
var name by nameProperty
|
||||
|
||||
val sourceDirectoryProperty = SimpleObjectProperty<File>()
|
||||
val sourceDirectory by sourceDirectoryProperty
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.project.model
|
||||
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.*
|
||||
import java.io.File
|
||||
|
||||
class Project {
|
||||
val nameProperty = SimpleStringProperty()
|
||||
var name by nameProperty
|
||||
|
||||
val sourceDirectoryProperty = SimpleObjectProperty<File>()
|
||||
val sourceDirectory by sourceDirectoryProperty
|
||||
}
|
||||
|
||||
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProjectDeserializer.kt
Executable file → Normal file
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProjectDeserializer.kt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
package com.bartlomiejpluta.base.editor.project.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.common.serial.Deserializer
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
|
||||
package com.bartlomiejpluta.base.editor.project.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.common.serial.Deserializer
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
|
||||
interface ProjectDeserializer : Deserializer<Project>
|
||||
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProjectSerializer.kt
Executable file → Normal file
10
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProjectSerializer.kt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
package com.bartlomiejpluta.base.editor.project.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.common.serial.Serializer
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
|
||||
package com.bartlomiejpluta.base.editor.project.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.common.serial.Serializer
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
|
||||
interface ProjectSerializer : Serializer<Project>
|
||||
34
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt
Executable file → Normal file
34
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectDeserializer.kt
Executable file → Normal file
@@ -1,18 +1,18 @@
|
||||
package com.bartlomiejpluta.base.editor.project.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import com.bartlomiejpluta.base.proto.ProjectProto
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.InputStream
|
||||
|
||||
@Component
|
||||
class ProtobufProjectDeserializer : ProjectDeserializer {
|
||||
|
||||
override fun deserialize(input: InputStream): Project {
|
||||
val proto = ProjectProto.Project.parseFrom(input)
|
||||
val project = Project()
|
||||
project.name = proto.name
|
||||
|
||||
return project
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.project.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import com.bartlomiejpluta.base.proto.ProjectProto
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.InputStream
|
||||
|
||||
@Component
|
||||
class ProtobufProjectDeserializer : ProjectDeserializer {
|
||||
|
||||
override fun deserialize(input: InputStream): Project {
|
||||
val proto = ProjectProto.Project.parseFrom(input)
|
||||
val project = Project()
|
||||
project.name = proto.name
|
||||
|
||||
return project
|
||||
}
|
||||
}
|
||||
30
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt
Executable file → Normal file
30
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/serial/ProtobufProjectSerializer.kt
Executable file → Normal file
@@ -1,16 +1,16 @@
|
||||
package com.bartlomiejpluta.base.editor.project.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import com.bartlomiejpluta.base.proto.ProjectProto
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.OutputStream
|
||||
|
||||
@Component
|
||||
class ProtobufProjectSerializer : ProjectSerializer {
|
||||
|
||||
override fun serialize(item: Project, output: OutputStream) {
|
||||
val proto = ProjectProto.Project.newBuilder()
|
||||
proto.name = item.name
|
||||
proto.build().writeTo(output)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.project.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import com.bartlomiejpluta.base.proto.ProjectProto
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.OutputStream
|
||||
|
||||
@Component
|
||||
class ProtobufProjectSerializer : ProjectSerializer {
|
||||
|
||||
override fun serialize(item: Project, output: OutputStream) {
|
||||
val proto = ProjectProto.Project.newBuilder()
|
||||
proto.name = item.name
|
||||
proto.build().writeTo(output)
|
||||
}
|
||||
}
|
||||
190
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/view/ProjectSettingsFragment.kt
Executable file → Normal file
190
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/view/ProjectSettingsFragment.kt
Executable file → Normal file
@@ -1,96 +1,96 @@
|
||||
package com.bartlomiejpluta.base.editor.project.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.project.viewmodel.ProjectVM
|
||||
import javafx.beans.binding.Bindings
|
||||
import javafx.beans.binding.Bindings.createStringBinding
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.*
|
||||
import java.io.File
|
||||
|
||||
class ProjectSettingsFragment : Fragment("Project Settings") {
|
||||
private val projectVM = find<ProjectVM>(FX.defaultScope)
|
||||
|
||||
private val rootDirectory = SimpleStringProperty("")
|
||||
private val projectDirectory = SimpleStringProperty("")
|
||||
private val directory = createStringBinding({
|
||||
File(rootDirectory.value, projectDirectory.value).absolutePath
|
||||
}, rootDirectory, projectDirectory)
|
||||
|
||||
init {
|
||||
directory.addListener { _, _, path -> projectVM.sourceDirectoryProperty.value = File(path) }
|
||||
}
|
||||
|
||||
var result = false
|
||||
private set
|
||||
|
||||
override val root = form {
|
||||
fieldset("Project Settings") {
|
||||
field("Project Name") {
|
||||
textfield(projectVM.nameProperty) {
|
||||
required()
|
||||
trimWhitespace()
|
||||
whenDocked { requestFocus() }
|
||||
}
|
||||
}
|
||||
|
||||
field("Project Location") {
|
||||
hbox {
|
||||
textfield(rootDirectory) {
|
||||
trimWhitespace()
|
||||
|
||||
projectVM.validationContext.addValidator(this, rootDirectory) {
|
||||
when {
|
||||
it.isNullOrBlank() -> error("Field is required")
|
||||
!File(it).exists() -> error("Provide valid path to the direction")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button("Choose") {
|
||||
action {
|
||||
rootDirectory.value = chooseDirectory("Project Location")?.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
field("Project Directory Name") {
|
||||
textfield(projectDirectory) {
|
||||
trimWhitespace()
|
||||
|
||||
projectVM.validationContext.addValidator(this, projectDirectory) {
|
||||
when {
|
||||
it.isNullOrBlank() -> error("Field is required")
|
||||
File(directory.value).exists() -> error("The directory ${directory.value} already exists")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label(Bindings.format("Directory:\n%s", directory))
|
||||
}
|
||||
|
||||
buttonbar {
|
||||
button("Ok") {
|
||||
action {
|
||||
projectVM.commit {
|
||||
result = true
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
shortcut("Enter")
|
||||
}
|
||||
|
||||
button("Reset") {
|
||||
action { projectVM.rollback() }
|
||||
}
|
||||
|
||||
button("Cancel") {
|
||||
action { close() }
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.project.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.project.viewmodel.ProjectVM
|
||||
import javafx.beans.binding.Bindings
|
||||
import javafx.beans.binding.Bindings.createStringBinding
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.*
|
||||
import java.io.File
|
||||
|
||||
class ProjectSettingsFragment : Fragment("Project Settings") {
|
||||
private val projectVM = find<ProjectVM>(FX.defaultScope)
|
||||
|
||||
private val rootDirectory = SimpleStringProperty("")
|
||||
private val projectDirectory = SimpleStringProperty("")
|
||||
private val directory = createStringBinding({
|
||||
File(rootDirectory.value, projectDirectory.value).absolutePath
|
||||
}, rootDirectory, projectDirectory)
|
||||
|
||||
init {
|
||||
directory.addListener { _, _, path -> projectVM.sourceDirectoryProperty.value = File(path) }
|
||||
}
|
||||
|
||||
var result = false
|
||||
private set
|
||||
|
||||
override val root = form {
|
||||
fieldset("Project Settings") {
|
||||
field("Project Name") {
|
||||
textfield(projectVM.nameProperty) {
|
||||
required()
|
||||
trimWhitespace()
|
||||
whenDocked { requestFocus() }
|
||||
}
|
||||
}
|
||||
|
||||
field("Project Location") {
|
||||
hbox {
|
||||
textfield(rootDirectory) {
|
||||
trimWhitespace()
|
||||
|
||||
projectVM.validationContext.addValidator(this, rootDirectory) {
|
||||
when {
|
||||
it.isNullOrBlank() -> error("Field is required")
|
||||
!File(it).exists() -> error("Provide valid path to the direction")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button("Choose") {
|
||||
action {
|
||||
rootDirectory.value = chooseDirectory("Project Location")?.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
field("Project Directory Name") {
|
||||
textfield(projectDirectory) {
|
||||
trimWhitespace()
|
||||
|
||||
projectVM.validationContext.addValidator(this, projectDirectory) {
|
||||
when {
|
||||
it.isNullOrBlank() -> error("Field is required")
|
||||
File(directory.value).exists() -> error("The directory ${directory.value} already exists")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label(Bindings.format("Directory:\n%s", directory))
|
||||
}
|
||||
|
||||
buttonbar {
|
||||
button("Ok") {
|
||||
action {
|
||||
projectVM.commit {
|
||||
result = true
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
shortcut("Enter")
|
||||
}
|
||||
|
||||
button("Reset") {
|
||||
action { projectVM.rollback() }
|
||||
}
|
||||
|
||||
button("Cancel") {
|
||||
action { close() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/viewmodel/ProjectVM.kt
Executable file → Normal file
22
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/viewmodel/ProjectVM.kt
Executable file → Normal file
@@ -1,12 +1,12 @@
|
||||
package com.bartlomiejpluta.base.editor.project.viewmodel
|
||||
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import tornadofx.*
|
||||
|
||||
class ProjectVM(project: Project) : ItemViewModel<Project>(project) {
|
||||
val nameProperty = bind(Project::nameProperty)
|
||||
val name by nameProperty
|
||||
|
||||
val sourceDirectoryProperty = bind(Project::sourceDirectoryProperty)
|
||||
val sourceDirectory by sourceDirectoryProperty
|
||||
package com.bartlomiejpluta.base.editor.project.viewmodel
|
||||
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
import tornadofx.*
|
||||
|
||||
class ProjectVM(project: Project) : ItemViewModel<Project>(project) {
|
||||
val nameProperty = bind(Project::nameProperty)
|
||||
val name by nameProperty
|
||||
|
||||
val sourceDirectoryProperty = bind(Project::sourceDirectoryProperty)
|
||||
val sourceDirectory by sourceDirectoryProperty
|
||||
}
|
||||
34
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEvent.kt
Executable file → Normal file
34
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEvent.kt
Executable file → Normal file
@@ -1,18 +1,18 @@
|
||||
package com.bartlomiejpluta.base.editor.render.input
|
||||
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||
import javafx.event.EventType
|
||||
import javafx.scene.input.MouseButton
|
||||
import javafx.scene.input.MouseEvent
|
||||
|
||||
class MapMouseEvent(val row: Int, val column: Int, val type: EventType<out MouseEvent>, val button: MouseButton) {
|
||||
|
||||
companion object {
|
||||
fun of(event: MouseEvent, tileSet: TileSet) = MapMouseEvent(
|
||||
(event.y / tileSet.tileHeight).toInt(),
|
||||
(event.x / tileSet.tileWidth).toInt(),
|
||||
event.eventType,
|
||||
event.button
|
||||
)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.render.input
|
||||
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||
import javafx.event.EventType
|
||||
import javafx.scene.input.MouseButton
|
||||
import javafx.scene.input.MouseEvent
|
||||
|
||||
class MapMouseEvent(val row: Int, val column: Int, val type: EventType<out MouseEvent>, val button: MouseButton) {
|
||||
|
||||
companion object {
|
||||
fun of(event: MouseEvent, tileSet: TileSet) = MapMouseEvent(
|
||||
(event.y / tileSet.tileHeight).toInt(),
|
||||
(event.x / tileSet.tileWidth).toInt(),
|
||||
event.eventType,
|
||||
event.button
|
||||
)
|
||||
}
|
||||
}
|
||||
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEventHandler.kt
Executable file → Normal file
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEventHandler.kt
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
package com.bartlomiejpluta.base.editor.render.input
|
||||
|
||||
interface MapMouseEventHandler {
|
||||
fun handleMouseInput(event: MapMouseEvent)
|
||||
package com.bartlomiejpluta.base.editor.render.input
|
||||
|
||||
interface MapMouseEventHandler {
|
||||
fun handleMouseInput(event: MapMouseEvent)
|
||||
}
|
||||
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/model/Renderable.kt
Executable file → Normal file
12
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/model/Renderable.kt
Executable file → Normal file
@@ -1,7 +1,7 @@
|
||||
package com.bartlomiejpluta.base.editor.render.model
|
||||
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
|
||||
interface Renderable {
|
||||
fun render(gc: GraphicsContext)
|
||||
package com.bartlomiejpluta.base.editor.render.model
|
||||
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
|
||||
interface Renderable {
|
||||
fun render(gc: GraphicsContext)
|
||||
}
|
||||
14
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/manager/UIDManager.kt
Executable file → Normal file
14
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/manager/UIDManager.kt
Executable file → Normal file
@@ -1,8 +1,8 @@
|
||||
package com.bartlomiejpluta.base.editor.resource.uid.manager
|
||||
|
||||
import com.bartlomiejpluta.base.editor.resource.uid.model.UIDTarget
|
||||
|
||||
interface UIDManager {
|
||||
fun nextUID(target: UIDTarget): String
|
||||
fun loadData(target: UIDTarget, uids: Set<String>)
|
||||
package com.bartlomiejpluta.base.editor.resource.uid.manager
|
||||
|
||||
import com.bartlomiejpluta.base.editor.resource.uid.model.UIDTarget
|
||||
|
||||
interface UIDManager {
|
||||
fun nextUID(target: UIDTarget): String
|
||||
fun loadData(target: UIDTarget, uids: Set<String>)
|
||||
}
|
||||
50
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/manager/UUIDBasedUIDManager.kt
Executable file → Normal file
50
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/manager/UUIDBasedUIDManager.kt
Executable file → Normal file
@@ -1,26 +1,26 @@
|
||||
package com.bartlomiejpluta.base.editor.resource.uid.manager
|
||||
|
||||
import com.bartlomiejpluta.base.editor.resource.uid.model.UIDTarget
|
||||
import org.springframework.stereotype.Component
|
||||
import java.util.*
|
||||
|
||||
@Component
|
||||
class UUIDBasedUIDManager : UIDManager {
|
||||
private val registry = mutableMapOf<UIDTarget, Set<String>>()
|
||||
|
||||
override fun nextUID(target: UIDTarget): String {
|
||||
val set = registry.putIfAbsent(target, mutableSetOf())!!
|
||||
|
||||
var uid = ""
|
||||
|
||||
do {
|
||||
uid = UUID.randomUUID().toString()
|
||||
} while (uid !in set)
|
||||
|
||||
return uid
|
||||
}
|
||||
|
||||
override fun loadData(target: UIDTarget, uids: Set<String>) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.resource.uid.manager
|
||||
|
||||
import com.bartlomiejpluta.base.editor.resource.uid.model.UIDTarget
|
||||
import org.springframework.stereotype.Component
|
||||
import java.util.*
|
||||
|
||||
@Component
|
||||
class UUIDBasedUIDManager : UIDManager {
|
||||
private val registry = mutableMapOf<UIDTarget, Set<String>>()
|
||||
|
||||
override fun nextUID(target: UIDTarget): String {
|
||||
val set = registry.putIfAbsent(target, mutableSetOf())!!
|
||||
|
||||
var uid = ""
|
||||
|
||||
do {
|
||||
uid = UUID.randomUUID().toString()
|
||||
} while (uid !in set)
|
||||
|
||||
return uid
|
||||
}
|
||||
|
||||
override fun loadData(target: UIDTarget, uids: Set<String>) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/model/UIDTarget.kt
Executable file → Normal file
8
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/resource/uid/model/UIDTarget.kt
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
package com.bartlomiejpluta.base.editor.resource.uid.model
|
||||
|
||||
enum class UIDTarget {
|
||||
MAP
|
||||
package com.bartlomiejpluta.base.editor.resource.uid.model
|
||||
|
||||
enum class UIDTarget {
|
||||
MAP
|
||||
}
|
||||
136
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt
Executable file → Normal file
136
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt
Executable file → Normal file
@@ -1,69 +1,69 @@
|
||||
package com.bartlomiejpluta.base.editor.tileset.canvas
|
||||
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEventHandler
|
||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
import javafx.scene.input.MouseButton
|
||||
import javafx.scene.input.MouseEvent
|
||||
import javafx.scene.paint.Color
|
||||
|
||||
class TileSetCanvas(private val gameMapVM: GameMapVM, private val selection: TileSetSelection) : Renderable, MapMouseEventHandler {
|
||||
private var mouseRow = -1
|
||||
private var mouseColumn = -1
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
gc.clearRect(0.0, 0.0, gc.canvas.width, gc.canvas.height)
|
||||
|
||||
renderTiles(gc)
|
||||
selection.render(gc)
|
||||
}
|
||||
|
||||
private fun renderTiles(gc: GraphicsContext) {
|
||||
gameMapVM.tileSet.forEach { row, column, tile ->
|
||||
gc.fill = if ((row + column) % 2 == 0) BACKGROUND_COLOR1 else BACKGROUND_COLOR2
|
||||
gc.fillRect(
|
||||
column * tile.image.width,
|
||||
row * tile.image.height,
|
||||
gameMapVM.tileSet.tileWidth.toDouble(),
|
||||
gameMapVM.tileSet.tileHeight.toDouble()
|
||||
)
|
||||
gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleMouseInput(event: MapMouseEvent) {
|
||||
mouseRow = event.row
|
||||
mouseColumn = event.column
|
||||
|
||||
when (event.type) {
|
||||
MouseEvent.MOUSE_PRESSED -> beginSelection(event)
|
||||
MouseEvent.MOUSE_DRAGGED -> proceedSelection(event)
|
||||
MouseEvent.MOUSE_RELEASED -> finishSelection(event)
|
||||
}
|
||||
}
|
||||
|
||||
private fun beginSelection(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY) {
|
||||
selection.begin(event.row.toDouble(), event.column.toDouble())
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedSelection(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY) {
|
||||
selection.proceed(event.row.toDouble(), event.column.toDouble())
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishSelection(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY) {
|
||||
selection.finish(event.row.toDouble(), event.column.toDouble())
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val BACKGROUND_COLOR1 = Color.color(1.0, 1.0, 1.0, 1.0)
|
||||
private val BACKGROUND_COLOR2 = Color.color(0.95, 0.95, 0.95, 0.95)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.tileset.canvas
|
||||
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEventHandler
|
||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
import javafx.scene.input.MouseButton
|
||||
import javafx.scene.input.MouseEvent
|
||||
import javafx.scene.paint.Color
|
||||
|
||||
class TileSetCanvas(private val gameMapVM: GameMapVM, private val selection: TileSetSelection) : Renderable, MapMouseEventHandler {
|
||||
private var mouseRow = -1
|
||||
private var mouseColumn = -1
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
gc.clearRect(0.0, 0.0, gc.canvas.width, gc.canvas.height)
|
||||
|
||||
renderTiles(gc)
|
||||
selection.render(gc)
|
||||
}
|
||||
|
||||
private fun renderTiles(gc: GraphicsContext) {
|
||||
gameMapVM.tileSet.forEach { row, column, tile ->
|
||||
gc.fill = if ((row + column) % 2 == 0) BACKGROUND_COLOR1 else BACKGROUND_COLOR2
|
||||
gc.fillRect(
|
||||
column * tile.image.width,
|
||||
row * tile.image.height,
|
||||
gameMapVM.tileSet.tileWidth.toDouble(),
|
||||
gameMapVM.tileSet.tileHeight.toDouble()
|
||||
)
|
||||
gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleMouseInput(event: MapMouseEvent) {
|
||||
mouseRow = event.row
|
||||
mouseColumn = event.column
|
||||
|
||||
when (event.type) {
|
||||
MouseEvent.MOUSE_PRESSED -> beginSelection(event)
|
||||
MouseEvent.MOUSE_DRAGGED -> proceedSelection(event)
|
||||
MouseEvent.MOUSE_RELEASED -> finishSelection(event)
|
||||
}
|
||||
}
|
||||
|
||||
private fun beginSelection(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY) {
|
||||
selection.begin(event.row.toDouble(), event.column.toDouble())
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedSelection(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY) {
|
||||
selection.proceed(event.row.toDouble(), event.column.toDouble())
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishSelection(event: MapMouseEvent) {
|
||||
if (event.button == MouseButton.PRIMARY) {
|
||||
selection.finish(event.row.toDouble(), event.column.toDouble())
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val BACKGROUND_COLOR1 = Color.color(1.0, 1.0, 1.0, 1.0)
|
||||
private val BACKGROUND_COLOR2 = Color.color(0.95, 0.95, 0.95, 0.95)
|
||||
}
|
||||
}
|
||||
158
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetSelection.kt
Executable file → Normal file
158
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetSelection.kt
Executable file → Normal file
@@ -1,80 +1,80 @@
|
||||
package com.bartlomiejpluta.base.editor.tileset.canvas
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
import javafx.scene.paint.Color
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
class TileSetSelection(private val gameMapVM: GameMapVM, private val brushVM: BrushVM) : Renderable {
|
||||
private var startRow = 0.0
|
||||
private var startColumn = 0.0
|
||||
private var offsetRow = 0.0
|
||||
private var offsetColumn = 0.0
|
||||
private var x = 0.0
|
||||
private var y = 0.0
|
||||
private var width = gameMapVM.tileSet.tileWidth.toDouble()
|
||||
private var height = gameMapVM.tileSet.tileHeight.toDouble()
|
||||
|
||||
|
||||
fun begin(row: Double, column: Double) {
|
||||
startRow = row
|
||||
offsetRow = 0.0
|
||||
startColumn = column
|
||||
offsetColumn = 0.0
|
||||
|
||||
updateRect(row, column)
|
||||
}
|
||||
|
||||
private fun updateRect(row: Double, column: Double) {
|
||||
x = min(column, startColumn) * gameMapVM.tileSet.tileWidth
|
||||
y = min(row, startRow) * gameMapVM.tileSet.tileHeight
|
||||
width = (offsetColumn + 1) * gameMapVM.tileSet.tileWidth
|
||||
height = (offsetRow + 1) * gameMapVM.tileSet.tileHeight
|
||||
}
|
||||
|
||||
fun proceed(row: Double, column: Double) {
|
||||
offsetRow = abs(row - startRow)
|
||||
offsetColumn = abs(column - startColumn)
|
||||
|
||||
updateRect(row, column)
|
||||
}
|
||||
|
||||
fun finish(row: Double, column: Double) {
|
||||
proceed(row, column)
|
||||
|
||||
startRow = min(row, startRow)
|
||||
startColumn = min(column, startColumn)
|
||||
|
||||
val firstRow = startRow.toInt()
|
||||
val firstColumn = startColumn.toInt()
|
||||
val rows = offsetRow.toInt() + 1
|
||||
val columns = offsetColumn.toInt() + 1
|
||||
|
||||
val brushArray = Array(rows) { rowIndex ->
|
||||
Array(columns) { columnIndex ->
|
||||
gameMapVM.tileSet.getTile(firstRow + rowIndex, firstColumn + columnIndex)
|
||||
}
|
||||
}
|
||||
|
||||
brushVM.item = Brush.of(brushArray)
|
||||
brushVM.commit()
|
||||
}
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
gc.fill = SELECTION_FILL_COLOR
|
||||
gc.fillRect(x, y, width, height)
|
||||
|
||||
gc.stroke = SELECTION_STROKE_COLOR
|
||||
gc.strokeRect(x, y, width, height)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val SELECTION_FILL_COLOR = Color.color(0.0, 0.7, 1.0, 0.4)
|
||||
private val SELECTION_STROKE_COLOR = Color.color(0.0, 0.7, 1.0, 1.0)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.tileset.canvas
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
||||
import com.bartlomiejpluta.base.editor.render.model.Renderable
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.scene.canvas.GraphicsContext
|
||||
import javafx.scene.paint.Color
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
class TileSetSelection(private val gameMapVM: GameMapVM, private val brushVM: BrushVM) : Renderable {
|
||||
private var startRow = 0.0
|
||||
private var startColumn = 0.0
|
||||
private var offsetRow = 0.0
|
||||
private var offsetColumn = 0.0
|
||||
private var x = 0.0
|
||||
private var y = 0.0
|
||||
private var width = gameMapVM.tileSet.tileWidth.toDouble()
|
||||
private var height = gameMapVM.tileSet.tileHeight.toDouble()
|
||||
|
||||
|
||||
fun begin(row: Double, column: Double) {
|
||||
startRow = row
|
||||
offsetRow = 0.0
|
||||
startColumn = column
|
||||
offsetColumn = 0.0
|
||||
|
||||
updateRect(row, column)
|
||||
}
|
||||
|
||||
private fun updateRect(row: Double, column: Double) {
|
||||
x = min(column, startColumn) * gameMapVM.tileSet.tileWidth
|
||||
y = min(row, startRow) * gameMapVM.tileSet.tileHeight
|
||||
width = (offsetColumn + 1) * gameMapVM.tileSet.tileWidth
|
||||
height = (offsetRow + 1) * gameMapVM.tileSet.tileHeight
|
||||
}
|
||||
|
||||
fun proceed(row: Double, column: Double) {
|
||||
offsetRow = abs(row - startRow)
|
||||
offsetColumn = abs(column - startColumn)
|
||||
|
||||
updateRect(row, column)
|
||||
}
|
||||
|
||||
fun finish(row: Double, column: Double) {
|
||||
proceed(row, column)
|
||||
|
||||
startRow = min(row, startRow)
|
||||
startColumn = min(column, startColumn)
|
||||
|
||||
val firstRow = startRow.toInt()
|
||||
val firstColumn = startColumn.toInt()
|
||||
val rows = offsetRow.toInt() + 1
|
||||
val columns = offsetColumn.toInt() + 1
|
||||
|
||||
val brushArray = Array(rows) { rowIndex ->
|
||||
Array(columns) { columnIndex ->
|
||||
gameMapVM.tileSet.getTile(firstRow + rowIndex, firstColumn + columnIndex)
|
||||
}
|
||||
}
|
||||
|
||||
brushVM.item = Brush.of(brushArray)
|
||||
brushVM.commit()
|
||||
}
|
||||
|
||||
override fun render(gc: GraphicsContext) {
|
||||
gc.fill = SELECTION_FILL_COLOR
|
||||
gc.fillRect(x, y, width, height)
|
||||
|
||||
gc.stroke = SELECTION_STROKE_COLOR
|
||||
gc.strokeRect(x, y, width, height)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val SELECTION_FILL_COLOR = Color.color(0.0, 0.7, 1.0, 0.4)
|
||||
private val SELECTION_STROKE_COLOR = Color.color(0.0, 0.7, 1.0, 1.0)
|
||||
}
|
||||
}
|
||||
82
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/component/TileSetPane.kt
Executable file → Normal file
82
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/component/TileSetPane.kt
Executable file → Normal file
@@ -1,42 +1,42 @@
|
||||
package com.bartlomiejpluta.base.editor.tileset.component
|
||||
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||
import com.bartlomiejpluta.base.editor.tileset.canvas.TileSetCanvas
|
||||
import com.bartlomiejpluta.base.editor.tileset.canvas.TileSetSelection
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.event.EventHandler
|
||||
import javafx.scene.canvas.Canvas
|
||||
import javafx.scene.input.MouseEvent
|
||||
|
||||
class TileSetPane(private val gameMapVM: GameMapVM, brushVM: BrushVM) : Canvas(), EventHandler<MouseEvent> {
|
||||
private val selection = TileSetSelection(gameMapVM, brushVM)
|
||||
private val tileSetCanvas = TileSetCanvas(gameMapVM, selection)
|
||||
|
||||
init {
|
||||
onMouseMoved = this
|
||||
onMouseDragged = this
|
||||
onMousePressed = this
|
||||
onMouseReleased = this
|
||||
|
||||
width = gameMapVM.tileSet.width.toDouble()
|
||||
height = gameMapVM.tileSet.height.toDouble()
|
||||
|
||||
|
||||
brushVM.itemProperty.addListener { _, _, _ -> render() }
|
||||
|
||||
render()
|
||||
}
|
||||
|
||||
private fun render() {
|
||||
tileSetCanvas.render(graphicsContext2D)
|
||||
}
|
||||
|
||||
override fun handle(event: MouseEvent?) {
|
||||
if (event != null) {
|
||||
tileSetCanvas.handleMouseInput(MapMouseEvent.of(event, gameMapVM.tileSet))
|
||||
}
|
||||
|
||||
tileSetCanvas.render(graphicsContext2D)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.tileset.component
|
||||
|
||||
import com.bartlomiejpluta.base.editor.render.input.MapMouseEvent
|
||||
import com.bartlomiejpluta.base.editor.tileset.canvas.TileSetCanvas
|
||||
import com.bartlomiejpluta.base.editor.tileset.canvas.TileSetSelection
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import javafx.event.EventHandler
|
||||
import javafx.scene.canvas.Canvas
|
||||
import javafx.scene.input.MouseEvent
|
||||
|
||||
class TileSetPane(private val gameMapVM: GameMapVM, brushVM: BrushVM) : Canvas(), EventHandler<MouseEvent> {
|
||||
private val selection = TileSetSelection(gameMapVM, brushVM)
|
||||
private val tileSetCanvas = TileSetCanvas(gameMapVM, selection)
|
||||
|
||||
init {
|
||||
onMouseMoved = this
|
||||
onMouseDragged = this
|
||||
onMousePressed = this
|
||||
onMouseReleased = this
|
||||
|
||||
width = gameMapVM.tileSet.width.toDouble()
|
||||
height = gameMapVM.tileSet.height.toDouble()
|
||||
|
||||
|
||||
brushVM.itemProperty.addListener { _, _, _ -> render() }
|
||||
|
||||
render()
|
||||
}
|
||||
|
||||
private fun render() {
|
||||
tileSetCanvas.render(graphicsContext2D)
|
||||
}
|
||||
|
||||
override fun handle(event: MouseEvent?) {
|
||||
if (event != null) {
|
||||
tileSetCanvas.handleMouseInput(MapMouseEvent.of(event, gameMapVM.tileSet))
|
||||
}
|
||||
|
||||
tileSetCanvas.render(graphicsContext2D)
|
||||
}
|
||||
}
|
||||
108
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/model/Tile.kt
Executable file → Normal file
108
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/model/Tile.kt
Executable file → Normal file
@@ -1,55 +1,55 @@
|
||||
package com.bartlomiejpluta.base.editor.tileset.model
|
||||
|
||||
import javafx.scene.image.Image
|
||||
|
||||
import javafx.scene.image.PixelReader
|
||||
|
||||
import javafx.scene.image.WritableImage
|
||||
|
||||
|
||||
class Tile(
|
||||
tileSet: TileSet,
|
||||
row: Int,
|
||||
column: Int,
|
||||
val image: Image,
|
||||
) {
|
||||
val id = row * tileSet.columns + column
|
||||
|
||||
private fun cloneImage(image: Image): Image {
|
||||
val height = image.height.toInt()
|
||||
val width = image.width.toInt()
|
||||
val pixelReader = image.pixelReader
|
||||
val writableImage = WritableImage(width, height)
|
||||
val pixelWriter = writableImage.pixelWriter
|
||||
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val color = pixelReader.getColor(x, y)
|
||||
pixelWriter.setColor(x, y, color)
|
||||
}
|
||||
}
|
||||
return writableImage
|
||||
}
|
||||
|
||||
fun scale(image: Image, factor: Int): Image {
|
||||
val width = image.width.toInt()
|
||||
val height = image.height.toInt()
|
||||
val output = WritableImage(width * factor, height * factor)
|
||||
|
||||
val reader: PixelReader = image.pixelReader
|
||||
val writer = output.pixelWriter
|
||||
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val argb = reader.getArgb(x, y)
|
||||
for (dy in 0 until factor) {
|
||||
for (dx in 0 until factor) {
|
||||
writer.setArgb(x * factor + dx, y * factor + dy, argb)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.tileset.model
|
||||
|
||||
import javafx.scene.image.Image
|
||||
|
||||
import javafx.scene.image.PixelReader
|
||||
|
||||
import javafx.scene.image.WritableImage
|
||||
|
||||
|
||||
class Tile(
|
||||
tileSet: TileSet,
|
||||
row: Int,
|
||||
column: Int,
|
||||
val image: Image,
|
||||
) {
|
||||
val id = row * tileSet.columns + column
|
||||
|
||||
private fun cloneImage(image: Image): Image {
|
||||
val height = image.height.toInt()
|
||||
val width = image.width.toInt()
|
||||
val pixelReader = image.pixelReader
|
||||
val writableImage = WritableImage(width, height)
|
||||
val pixelWriter = writableImage.pixelWriter
|
||||
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val color = pixelReader.getColor(x, y)
|
||||
pixelWriter.setColor(x, y, color)
|
||||
}
|
||||
}
|
||||
return writableImage
|
||||
}
|
||||
|
||||
fun scale(image: Image, factor: Int): Image {
|
||||
val width = image.width.toInt()
|
||||
val height = image.height.toInt()
|
||||
val output = WritableImage(width * factor, height * factor)
|
||||
|
||||
val reader: PixelReader = image.pixelReader
|
||||
val writer = output.pixelWriter
|
||||
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val argb = reader.getArgb(x, y)
|
||||
for (dy in 0 until factor) {
|
||||
for (dx in 0 until factor) {
|
||||
writer.setArgb(x * factor + dx, y * factor + dy, argb)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
}
|
||||
124
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/model/TileSet.kt
Executable file → Normal file
124
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/model/TileSet.kt
Executable file → Normal file
@@ -1,63 +1,63 @@
|
||||
package com.bartlomiejpluta.base.editor.tileset.model
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.scene.image.Image
|
||||
import javafx.scene.image.PixelFormat
|
||||
import javafx.scene.image.WritableImage
|
||||
import tornadofx.getValue
|
||||
import tornadofx.toObservable
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
|
||||
class TileSet(private val image: Image, rows: Int, columns: Int) {
|
||||
val rowsProperty = SimpleIntegerProperty(rows)
|
||||
val rows by rowsProperty
|
||||
|
||||
val columnsProperty = SimpleIntegerProperty(columns)
|
||||
val columns by columnsProperty
|
||||
|
||||
val tileWidthProperty = SimpleIntegerProperty(image.width.toInt() / columns)
|
||||
val tileWidth by tileWidthProperty
|
||||
|
||||
val tileHeightProperty = SimpleIntegerProperty(image.height.toInt() / rows)
|
||||
val tileHeight by tileHeightProperty
|
||||
|
||||
val widthProperty = SimpleIntegerProperty(tileWidth * columns)
|
||||
val width by widthProperty
|
||||
|
||||
val heightProperty = SimpleIntegerProperty(tileHeight * rows)
|
||||
val height by heightProperty
|
||||
|
||||
val tiles = (0 until rows * columns).map { cropTile(it / columns, it % columns) }.toObservable()
|
||||
|
||||
val baseBrush: Brush
|
||||
get() = Brush.of(arrayOf(arrayOf(tiles[0])))
|
||||
|
||||
private fun cropTile(row: Int, column: Int): Tile {
|
||||
val reader = image.pixelReader
|
||||
val buffer = ByteBuffer.allocate(tileWidth * tileHeight * 4)
|
||||
reader.getPixels(
|
||||
column * tileWidth,
|
||||
row * tileHeight,
|
||||
tileWidth,
|
||||
tileHeight,
|
||||
PixelFormat.getByteBgraInstance(),
|
||||
buffer,
|
||||
4 * tileWidth
|
||||
)
|
||||
val tile = WritableImage(tileWidth, tileHeight)
|
||||
val writer = tile.pixelWriter
|
||||
writer.setPixels(0, 0, tileWidth, tileHeight, PixelFormat.getByteBgraInstance(), buffer, 4 * tileWidth)
|
||||
|
||||
return Tile(this, row, column, tile)
|
||||
}
|
||||
|
||||
fun getTile(row: Int, column: Int) = tiles[(row.coerceIn(0 until rows)) * columns + column.coerceIn(0 until columns)]
|
||||
|
||||
fun getTile(id: Int) = tiles[id]
|
||||
|
||||
fun forEach(consumer: (row: Int, column: Int, tile: Tile) -> Unit) = tiles.forEachIndexed { id, tile ->
|
||||
consumer(id / columns, id % columns, tile)
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.tileset.model
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.model.brush.Brush
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.scene.image.Image
|
||||
import javafx.scene.image.PixelFormat
|
||||
import javafx.scene.image.WritableImage
|
||||
import tornadofx.getValue
|
||||
import tornadofx.toObservable
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
|
||||
class TileSet(private val image: Image, rows: Int, columns: Int) {
|
||||
val rowsProperty = SimpleIntegerProperty(rows)
|
||||
val rows by rowsProperty
|
||||
|
||||
val columnsProperty = SimpleIntegerProperty(columns)
|
||||
val columns by columnsProperty
|
||||
|
||||
val tileWidthProperty = SimpleIntegerProperty(image.width.toInt() / columns)
|
||||
val tileWidth by tileWidthProperty
|
||||
|
||||
val tileHeightProperty = SimpleIntegerProperty(image.height.toInt() / rows)
|
||||
val tileHeight by tileHeightProperty
|
||||
|
||||
val widthProperty = SimpleIntegerProperty(tileWidth * columns)
|
||||
val width by widthProperty
|
||||
|
||||
val heightProperty = SimpleIntegerProperty(tileHeight * rows)
|
||||
val height by heightProperty
|
||||
|
||||
val tiles = (0 until rows * columns).map { cropTile(it / columns, it % columns) }.toObservable()
|
||||
|
||||
val baseBrush: Brush
|
||||
get() = Brush.of(arrayOf(arrayOf(tiles[0])))
|
||||
|
||||
private fun cropTile(row: Int, column: Int): Tile {
|
||||
val reader = image.pixelReader
|
||||
val buffer = ByteBuffer.allocate(tileWidth * tileHeight * 4)
|
||||
reader.getPixels(
|
||||
column * tileWidth,
|
||||
row * tileHeight,
|
||||
tileWidth,
|
||||
tileHeight,
|
||||
PixelFormat.getByteBgraInstance(),
|
||||
buffer,
|
||||
4 * tileWidth
|
||||
)
|
||||
val tile = WritableImage(tileWidth, tileHeight)
|
||||
val writer = tile.pixelWriter
|
||||
writer.setPixels(0, 0, tileWidth, tileHeight, PixelFormat.getByteBgraInstance(), buffer, 4 * tileWidth)
|
||||
|
||||
return Tile(this, row, column, tile)
|
||||
}
|
||||
|
||||
fun getTile(row: Int, column: Int) = tiles[(row.coerceIn(0 until rows)) * columns + column.coerceIn(0 until columns)]
|
||||
|
||||
fun getTile(id: Int) = tiles[id]
|
||||
|
||||
fun forEach(consumer: (row: Int, column: Int, tile: Tile) -> Unit) = tiles.forEachIndexed { id, tile ->
|
||||
consumer(id / columns, id % columns, tile)
|
||||
}
|
||||
}
|
||||
36
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/TileSetView.kt
Executable file → Normal file
36
editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/TileSetView.kt
Executable file → Normal file
@@ -1,19 +1,19 @@
|
||||
package com.bartlomiejpluta.base.editor.tileset.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.tileset.component.TileSetPane
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import tornadofx.View
|
||||
import tornadofx.plusAssign
|
||||
import tornadofx.scrollpane
|
||||
|
||||
class TileSetView : View() {
|
||||
private val gameMapVM = find<GameMapVM>()
|
||||
private val brushVM = find<BrushVM>()
|
||||
|
||||
private val tileSetPane = TileSetPane(gameMapVM, brushVM)
|
||||
|
||||
override val root = scrollpane {
|
||||
this += tileSetPane
|
||||
}
|
||||
package com.bartlomiejpluta.base.editor.tileset.view
|
||||
|
||||
import com.bartlomiejpluta.base.editor.tileset.component.TileSetPane
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.BrushVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import tornadofx.View
|
||||
import tornadofx.plusAssign
|
||||
import tornadofx.scrollpane
|
||||
|
||||
class TileSetView : View() {
|
||||
private val gameMapVM = find<GameMapVM>()
|
||||
private val brushVM = find<BrushVM>()
|
||||
|
||||
private val tileSetPane = TileSetPane(gameMapVM, brushVM)
|
||||
|
||||
override val root = scrollpane {
|
||||
this += tileSetPane
|
||||
}
|
||||
}
|
||||
4
editor/src/main/resources/application.yml
Executable file → Normal file
4
editor/src/main/resources/application.yml
Executable file → Normal file
@@ -1,3 +1,3 @@
|
||||
logging:
|
||||
level:
|
||||
logging:
|
||||
level:
|
||||
com.bartlomiejpluta.base.editor: DEBUG
|
||||
Reference in New Issue
Block a user