diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/select/SelectGraphicAssetFragment.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/select/SelectGraphicAssetFragment.kt index 3bb474d3..f028b217 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/select/SelectGraphicAssetFragment.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/select/SelectGraphicAssetFragment.kt @@ -1,12 +1,16 @@ package com.bartlomiejpluta.base.editor.asset.view.select import com.bartlomiejpluta.base.editor.asset.model.Asset +import javafx.beans.property.BooleanProperty import javafx.beans.property.SimpleObjectProperty +import javafx.beans.property.StringProperty import javafx.collections.ObservableList import tornadofx.* class SelectGraphicAssetFragment : Fragment("Select Asset") { val assets: ObservableList by param() + val cancelable: BooleanProperty by param(true.toProperty()) + val comment: StringProperty by param("".toProperty()) private val asset = SimpleObjectProperty() @@ -22,6 +26,12 @@ class SelectGraphicAssetFragment : Fragment("Select Asset") { } override val root = form { + if(comment.isNotEmpty.value) { + label(comment) { + visibleWhen(comment.isNotEmpty) + } + } + fieldset { this += selectGraphicAssetView.root } @@ -37,6 +47,7 @@ class SelectGraphicAssetFragment : Fragment("Select Asset") { } button("Cancel") { + visibleWhen(cancelable) action { close() } } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt index e98b2bb7..ca6fb713 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt @@ -4,16 +4,17 @@ import com.bartlomiejpluta.base.editor.animation.view.importing.ImportAnimationF import com.bartlomiejpluta.base.editor.animation.viewmodel.AnimationAssetDataVM import com.bartlomiejpluta.base.editor.asset.model.Asset import com.bartlomiejpluta.base.editor.asset.model.GraphicAsset +import com.bartlomiejpluta.base.editor.asset.view.select.SelectGraphicAssetFragment import com.bartlomiejpluta.base.editor.asset.viewmodel.GraphicAssetVM import com.bartlomiejpluta.base.editor.audio.view.importing.ImportSoundFragment import com.bartlomiejpluta.base.editor.audio.viewmodel.SoundAssetDataVM +import com.bartlomiejpluta.base.editor.characterset.view.importing.ImportCharacterSetFragment +import com.bartlomiejpluta.base.editor.characterset.viewmodel.CharacterSetAssetDataVM import com.bartlomiejpluta.base.editor.code.model.CodeScope import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM import com.bartlomiejpluta.base.editor.command.context.UndoableScope import com.bartlomiejpluta.base.editor.database.model.data.Query import com.bartlomiejpluta.base.editor.database.viewmodel.QueryVM -import com.bartlomiejpluta.base.editor.characterset.view.importing.ImportCharacterSetFragment -import com.bartlomiejpluta.base.editor.characterset.viewmodel.CharacterSetAssetDataVM import com.bartlomiejpluta.base.editor.event.SelectMainViewTabEvent import com.bartlomiejpluta.base.editor.file.model.FileNode import com.bartlomiejpluta.base.editor.file.model.ScriptAssetFileNode @@ -26,18 +27,20 @@ import com.bartlomiejpluta.base.editor.image.view.importing.ImportImageFragment import com.bartlomiejpluta.base.editor.image.viewmodel.ImageAssetDataVM import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset import com.bartlomiejpluta.base.editor.map.model.map.GameMap -import com.bartlomiejpluta.base.editor.map.view.wizard.MapCreationWizard -import com.bartlomiejpluta.base.editor.map.view.wizard.MapImportWizard +import com.bartlomiejpluta.base.editor.map.view.wizard.MapCreationFragment +import com.bartlomiejpluta.base.editor.map.view.wizard.MapImportFragment import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM import com.bartlomiejpluta.base.editor.project.context.ProjectContext import com.bartlomiejpluta.base.editor.project.model.Project import com.bartlomiejpluta.base.editor.project.view.ProjectSettingsFragment import com.bartlomiejpluta.base.editor.project.viewmodel.ProjectVM +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset import com.bartlomiejpluta.base.editor.tileset.view.importing.ImportTileSetFragment import com.bartlomiejpluta.base.editor.tileset.viewmodel.TileSetAssetDataVM import javafx.scene.control.TextInputDialog import javafx.stage.FileChooser +import javafx.stage.StageStyle import org.springframework.stereotype.Component import tornadofx.* import java.io.File @@ -68,10 +71,9 @@ class MainController : Controller() { val vm = GameMapBuilderVM() setInScope(vm, scope) - find(scope).apply { + find(scope).apply { onComplete { - val tileSet = projectContext.loadTileSet(vm.tileSetAsset.uid) - val map = GameMap(tileSet).apply { + val map = GameMap(vm.tileWidth.toDouble(), vm.tileHeight.toDouble()).apply { rows = vm.rows columns = vm.columns handler = vm.handler @@ -88,10 +90,28 @@ class MainController : Controller() { val scope = UndoableScope() val vm = GameMapBuilderVM() setInScope(vm, scope) - find(scope).apply { + find(scope).apply { onComplete { - val tileSet = projectContext.loadTileSet(vm.tileSetAsset.uid) - val map = projectContext.importMapFromFile(vm.name, vm.handler, File(vm.file), tileSet) + val map = projectContext.importMapFromFile(vm.name, vm.handler, File(vm.file)) { name, uid -> + var newUid = "" + + find>( + Scope(), + SelectGraphicAssetFragment::assets to projectContext.project?.tileSets!!, + SelectGraphicAssetFragment::comment to "You are importing a tile layer which originally was defined\nwith an other Tile Set asset data with UID: [$uid].\nPlease select asset you would like to apply for layer $name.\n".toProperty(), + SelectGraphicAssetFragment::cancelable to false.toProperty() + ).apply { + title = "Select Tile Set for layer $name" + + onComplete { + newUid = it.uid + } + + openModal(block = true, resizable = false, stageStyle = StageStyle.UNDECORATED) + } + + newUid + } openItems[scope] = GameMapVM(map) } @@ -121,11 +141,7 @@ class MainController : Controller() { } fun openScript( - fsNode: FileNode, - line: Int = 1, - column: Int = 1, - execute: ((String) -> Unit)? = null, - saveable: Boolean = true + fsNode: FileNode, line: Int = 1, column: Int = 1, execute: ((String) -> Unit)? = null, saveable: Boolean = true ) { val findScript = { script: CodeVM -> script.fileNode.absolutePath == fsNode.absolutePath } val updateExistingScope = { scope: CodeScope -> scope.setCaretPosition(line, column) } @@ -170,11 +186,9 @@ class MainController : Controller() { updateViewModel: (VM) -> Unit = {}, createItem: () -> Pair ) { - @Suppress("UNCHECKED_CAST") - val pair = openItems.entries - .filter { (_, item) -> item is VM } - .map { (scope, item) -> (scope as S) to (item as VM) } - .firstOrNull { (_, item) -> findItem(item) } + @Suppress("UNCHECKED_CAST") val pair = + openItems.entries.filter { (_, item) -> item is VM }.map { (scope, item) -> (scope as S) to (item as VM) } + .firstOrNull { (_, item) -> findItem(item) } if (pair == null) { val (scope, item) = createItem() @@ -277,11 +291,7 @@ class MainController : Controller() { width = 300.0 contentText = "Widget name" title = "New Widget" - } - .showAndWait() - .map(::WidgetAssetData) - .map(projectContext::createWidget) - .ifPresent(this::openScript) + }.showAndWait().map(::WidgetAssetData).map(projectContext::createWidget).ifPresent(this::openScript) } fun importSound() { diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt index 20b87d1f..890728ef 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapCanvas.kt @@ -11,7 +11,6 @@ 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 diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPainter.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPainter.kt index c0043a1a..b99c4eff 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPainter.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/canvas/MapPainter.kt @@ -21,8 +21,8 @@ class MapPainter( private val editorStateVM: EditorStateVM, private val paintingCallback: (PaintingTrace) -> Unit ) : Renderable, MapMouseEventHandler { - private val tileWidth = mapVM.tileSet.tileWidth.toDouble() - private val tileHeight = mapVM.tileSet.tileHeight.toDouble() + private val tileWidth = mapVM.tileWidth.toDouble() + private val tileHeight = mapVM.tileHeight.toDouble() private var cursor: PaintingCursor? = null private var currentTrace: PaintingTrace? = null diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/component/MapPane.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/component/MapPane.kt index 0f801a07..a3718528 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/component/MapPane.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/component/MapPane.kt @@ -47,7 +47,7 @@ class MapPane( override fun handle(event: MouseEvent?) { if (event != null) { - painter.handleMouseInput(MapMouseEvent.of(event, mapVM.tileSet)) + painter.handleMouseInput(MapMouseEvent.of(event, mapVM)) } mapCanvas.render(graphicsContext2D) diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt index bf7795ee..49425f4c 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt @@ -1,14 +1,20 @@ package com.bartlomiejpluta.base.editor.map.model.layer +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset import com.bartlomiejpluta.base.editor.tileset.model.Tile +import com.bartlomiejpluta.base.editor.tileset.model.TileSet +import javafx.beans.binding.Bindings import javafx.beans.property.SimpleStringProperty +import javafx.scene.image.Image import tornadofx.getValue import tornadofx.setValue +import tornadofx.toProperty class TileLayer( name: String, rows: Int, columns: Int, + tileSetAsset: TileSetAsset, layer: Array> = Array(rows) { Array(columns) { null } } ) : Layer { var layer = layer @@ -17,6 +23,21 @@ class TileLayer( override val nameProperty = SimpleStringProperty(name) override var name: String by nameProperty + val tileSetAssetProperty = tileSetAsset.toProperty() + var tileSetAsset by tileSetAssetProperty + + val tileSetProperty = Bindings.createObjectBinding({ + tileSetAssetProperty.value.file.inputStream().use { fis -> + TileSet( + tileSetAsset.uid, + tileSetAsset.name, + Image(fis), + tileSetAsset.rows, + tileSetAsset.columns + ) + } + }, tileSetAssetProperty) + override fun resize(rows: Int, columns: Int) { layer = Array(rows) { row -> Array(columns) { column -> diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt index c92cf833..142ac7cb 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt @@ -10,15 +10,12 @@ import tornadofx.getValue import tornadofx.setValue -class GameMap(val tileSet: TileSet) { +class GameMap(val tileWidth: Double, val tileHeight: Double) { val uidProperty = SimpleStringProperty() var uid by uidProperty val layers = FXCollections.observableArrayList(Layer.extractor()) - val tileWidth = tileSet.tileWidth.toDouble() - val tileHeight = tileSet.tileHeight.toDouble() - val rowsProperty = SimpleIntegerProperty(INITIAL_ROWS) var rows by rowsProperty diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMapBuilder.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMapBuilder.kt index 8977c736..54585a19 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMapBuilder.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMapBuilder.kt @@ -1,6 +1,7 @@ package com.bartlomiejpluta.base.editor.map.model.map import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset +import javafx.beans.property.SimpleDoubleProperty import javafx.beans.property.SimpleIntegerProperty import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleStringProperty @@ -9,12 +10,15 @@ import tornadofx.setValue import java.io.File class GameMapBuilder { - val tileSetAssetProperty = SimpleObjectProperty() - var tileSetAsset by tileSetAssetProperty - val nameProperty = SimpleStringProperty("") var name by nameProperty + val tileWidthProperty = SimpleIntegerProperty(32) + var tileWidth by tileWidthProperty + + val tileHeightProperty = SimpleIntegerProperty(32) + var tileHeight by tileHeightProperty + val rowsProperty = SimpleIntegerProperty(20) var rows by rowsProperty diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/parameter/layer/TileLayerParametersBinder.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/parameter/layer/TileLayerParametersBinder.kt new file mode 100644 index 00000000..8b69c77c --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/parameter/layer/TileLayerParametersBinder.kt @@ -0,0 +1,27 @@ +package com.bartlomiejpluta.base.editor.map.parameter.layer + +import com.bartlomiejpluta.base.editor.common.parameter.model.GraphicAssetParameter +import com.bartlomiejpluta.base.editor.common.parameter.model.Parameter +import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer +import com.bartlomiejpluta.base.editor.project.model.Project +import javafx.collections.ObservableList +import org.springframework.stereotype.Component + +@Component +class TileLayerParametersBinder : LayerParametersBinder { + override fun bind( + layer: TileLayer, + parameters: ObservableList>, + project: Project, + onCommit: () -> Unit + ) { + val tileSet = GraphicAssetParameter("tileSet", layer.tileSetAsset, true, project.tileSets) { _, _, submit -> + onCommit() + submit() + } + + tileSet.bindBidirectional(layer.tileSetAssetProperty) + + parameters.addAll(tileSet) + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt index 91b86e21..3a8ee51f 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt @@ -2,9 +2,10 @@ package com.bartlomiejpluta.base.editor.map.serial import com.bartlomiejpluta.base.editor.common.serial.Deserializer import com.bartlomiejpluta.base.editor.map.model.map.GameMap +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset import com.bartlomiejpluta.base.editor.tileset.model.TileSet import java.io.InputStream interface MapDeserializer : Deserializer { - fun deserialize(input: InputStream, tileSet: TileSet): GameMap + fun deserialize(input: InputStream, replaceTileSet: (String, String) -> String): GameMap } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt index 77dc93a5..56f51d71 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt @@ -6,6 +6,7 @@ import com.bartlomiejpluta.base.editor.map.model.layer.* import com.bartlomiejpluta.base.editor.map.model.map.GameMap import com.bartlomiejpluta.base.editor.map.model.obj.MapObject import com.bartlomiejpluta.base.editor.project.context.ProjectContext +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset import com.bartlomiejpluta.base.editor.tileset.model.Tile import com.bartlomiejpluta.base.editor.tileset.model.TileSet import com.bartlomiejpluta.base.proto.GameMapProto @@ -24,25 +25,11 @@ class ProtobufMapDeserializer : MapDeserializer { appContext.getBean(ProjectContext::class.java) } - override fun deserialize(input: InputStream): GameMap { + override fun deserialize(input: InputStream) = deserialize(input) { _, uid -> uid } + + override fun deserialize(input: InputStream, replaceTileSet: (String, String) -> String): GameMap { val proto = GameMapProto.GameMap.parseFrom(input) - val tileSet = projectContext.loadTileSet(proto.tileSetUID) - val map = GameMap(tileSet) - map.uid = proto.uid - map.rows = proto.rows - map.columns = proto.columns - map.handler = proto.handler - - proto.layersList.forEach { - map.layers.add(deserializeLayer(map.rows, map.columns, tileSet, it)) - } - - return map - } - - override fun deserialize(input: InputStream, tileSet: TileSet): GameMap { - val proto = GameMapProto.GameMap.parseFrom(input) - val map = GameMap(tileSet) + val map = GameMap(proto.tileWidth.toDouble(), proto.tileHeight.toDouble()) map.uid = proto.uid map.rows = proto.rows map.columns = proto.columns @@ -50,14 +37,14 @@ class ProtobufMapDeserializer : MapDeserializer { proto.layersList .filter { it.hasTileLayer() || it.hasObjectLayer() || it.hasColorLayer() } - .forEach { map.layers.add(deserializeLayer(map.rows, map.columns, tileSet, it)) } + .forEach { map.layers.add(deserializeLayer(map.rows, map.columns, it, replaceTileSet)) } return map } - private fun deserializeLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer { + private fun deserializeLayer(rows: Int, columns: Int, proto: GameMapProto.Layer, replaceTileSet: (String, String) -> String): Layer { return when { - proto.hasTileLayer() -> deserializeTileLayer(rows, columns, tileSet, proto) + proto.hasTileLayer() -> deserializeTileLayer(rows, columns, proto, replaceTileSet) proto.hasObjectLayer() -> deserializeObjectLayer(rows, columns, proto) proto.hasColorLayer() -> deserializeColorLayer(proto) proto.hasImageLayer() -> deserializeImageLayer(proto) @@ -66,8 +53,10 @@ class ProtobufMapDeserializer : MapDeserializer { } } - private fun deserializeTileLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer { + private fun deserializeTileLayer(rows: Int, columns: Int, proto: GameMapProto.Layer, replaceTileSet: (String, String) -> String): Layer { val layer: Array> = Array(rows) { Array(columns) { null } } + val tileSetAsset = projectContext.findTileSetAsset(replaceTileSet(proto.name, proto.tileLayer.tilesetUID)) + val tileSet = projectContext.loadTileSet(tileSetAsset.uid) proto.tileLayer.tilesList.forEachIndexed { index, tile -> layer[index / columns][index % columns] = when (tile) { @@ -76,7 +65,7 @@ class ProtobufMapDeserializer : MapDeserializer { } } - return TileLayer(proto.name, rows, columns, layer) + return TileLayer(proto.name, rows, columns, tileSetAsset, layer) } private fun deserializeObjectLayer(rows: Int, columns: Int, proto: GameMapProto.Layer): Layer { diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt index ec0f8d32..33a4ca90 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt @@ -16,7 +16,8 @@ class ProtobufMapSerializer : MapSerializer { protoMap.uid = item.uid protoMap.rows = item.rows protoMap.columns = item.columns - protoMap.tileSetUID = item.tileSet.uid + protoMap.tileWidth = item.tileWidth.toInt() + protoMap.tileHeight = item.tileHeight.toInt() protoMap.handler = item.handler item.layers.forEach { layer -> protoMap.addLayers(serializeLayer(layer)) } @@ -28,6 +29,7 @@ class ProtobufMapSerializer : MapSerializer { return when (layer) { is TileLayer -> layer.layer.flatMap { it.asIterable() } .fold(GameMapProto.TileLayer.newBuilder()) { acc, tile -> acc.addTiles((tile?.id?.plus(1)) ?: 0) } + .setTilesetUID(layer.tileSetAsset.uid) .build() .let { GameMapProto.Layer.newBuilder().setName(layer.name).setTileLayer(it).build() } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapLayerParameters.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapLayerParameters.kt index b338185b..8efe5a07 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapLayerParameters.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapLayerParameters.kt @@ -5,8 +5,10 @@ import com.bartlomiejpluta.base.editor.common.parameter.view.ParametersTableFrag import com.bartlomiejpluta.base.editor.event.RedrawMapRequestEvent import com.bartlomiejpluta.base.editor.map.model.layer.ColorLayer import com.bartlomiejpluta.base.editor.map.model.layer.ImageLayer +import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer import com.bartlomiejpluta.base.editor.map.parameter.layer.ColorLayerParametersBinder import com.bartlomiejpluta.base.editor.map.parameter.layer.ImageLayerParametersBinder +import com.bartlomiejpluta.base.editor.map.parameter.layer.TileLayerParametersBinder import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM import com.bartlomiejpluta.base.editor.project.context.ProjectContext import tornadofx.View @@ -20,6 +22,7 @@ class MapLayerParameters : View() { // of LayerParametersBinder<> type private val colorLayerParametersBinder: ColorLayerParametersBinder by di() private val imageLayerParametersBinder: ImageLayerParametersBinder by di() + private val tileLayerParametersBinder: TileLayerParametersBinder by di() private val parameters = observableListOf>() @@ -29,15 +32,16 @@ class MapLayerParameters : View() { parameters.clear() when (layer) { - is ColorLayer -> colorLayerParametersBinder.bind(layer, parameters, projectContext.project!!) { - fire( - RedrawMapRequestEvent - ) + is TileLayer -> tileLayerParametersBinder.bind(layer, parameters, projectContext.project!!) { + fire(RedrawMapRequestEvent) } + + is ColorLayer -> colorLayerParametersBinder.bind(layer, parameters, projectContext.project!!) { + fire(RedrawMapRequestEvent) + } + is ImageLayer -> imageLayerParametersBinder.bind(layer, parameters, projectContext.project!!) { - fire( - RedrawMapRequestEvent - ) + fire(RedrawMapRequestEvent) } } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapLayersView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapLayersView.kt index bf391af3..d9b3339a 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapLayersView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapLayersView.kt @@ -13,6 +13,7 @@ import com.bartlomiejpluta.base.editor.map.model.layer.* import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM import com.bartlomiejpluta.base.editor.project.context.ProjectContext +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset import javafx.collections.ObservableList import javafx.scene.control.ListCell import javafx.scene.control.ListView @@ -55,11 +56,21 @@ class MapLayersView : View() { menubutton(graphic = FontIcon("fa-plus")) { item("Tile Layer", graphic = FontIcon("fa-th-large")) { action { - val layer = TileLayer("Layer ${mapVM.layers.size + 1}", mapVM.rows, mapVM.columns) - val command = CreateLayerCommand(mapVM.item, layer) - command.execute() - layersPane.selectionModel.select(mapVM.layers.size - 1) - undoRedoService.push(command, scope) + val scope = UndoableScope() + find>( + scope, + SelectGraphicAssetFragment::assets to projectContext.project?.tileSets!! + ).apply { + onComplete { + val layer = TileLayer("Layer ${mapVM.layers.size + 1}", mapVM.rows, mapVM.columns, it) + val command = CreateLayerCommand(mapVM.item, layer) + command.execute() + layersPane.selectionModel.select(mapVM.layers.size - 1) + undoRedoService.push(command, scope) + } + + openModal(block = true, resizable = false) + } } } @@ -164,7 +175,7 @@ class MapLayersView : View() { override fun fromString(string: String?): Layer = cell.item.apply { string ?.takeIf { str -> str != name } - ?.takeIf { str -> layers.none { it.name == str }} + ?.takeIf { str -> layers.none { it.name == str } } ?.let { onUpdate(this, it) } } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapView.kt index 582197e5..d099e251 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/editor/MapView.kt @@ -40,7 +40,7 @@ class MapView : View() { } init { - brushVM.item = mapVM.tileSet.baseBrush +// brushVM.item = mapVM.tileSet.baseBrush brushVM.commit() subscribe { mapPane.render() } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapCreationBasicDataView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapCreationFragment.kt similarity index 54% rename from editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapCreationBasicDataView.kt rename to editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapCreationFragment.kt index e1590681..c833e086 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapCreationBasicDataView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapCreationFragment.kt @@ -1,11 +1,13 @@ package com.bartlomiejpluta.base.editor.map.view.wizard +import com.bartlomiejpluta.base.editor.map.model.map.GameMapBuilder import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM import com.bartlomiejpluta.base.editor.util.fx.TextFieldUtil import tornadofx.* -class MapCreationBasicDataView : View("Basic Data") { +class MapCreationFragment : Fragment("Basic Data") { private val mapBuilderVM = find() + private var onCompleteConsumer: ((GameMapBuilder) -> Unit)? = null override val complete = mapBuilderVM.valid( mapBuilderVM.nameProperty, @@ -14,6 +16,11 @@ class MapCreationBasicDataView : View("Basic Data") { mapBuilderVM.handlerProperty ) + fun onComplete(consumer: (GameMapBuilder) -> Unit) { + this.onCompleteConsumer = consumer + } + + override val root = form { fieldset("Map Settings") { field("Map name") { @@ -23,6 +30,36 @@ class MapCreationBasicDataView : View("Basic Data") { } } + field("Tile Width") { + spinner(min = 1, property = mapBuilderVM.tileWidthProperty, editable = true) { + required() + editor.textFormatter = TextFieldUtil.integerFormatter(mapBuilderVM.tileWidth) + + validator { + if (it?.toInt()?.let { value -> value <= 0 } != false) { + error("The tile width must be greater than 0") + } + + null + } + } + } + + field("Tile Height") { + spinner(min = 1, property = mapBuilderVM.tileHeightProperty, editable = true) { + required() + editor.textFormatter = TextFieldUtil.integerFormatter(mapBuilderVM.tileHeight) + + validator { + if (it?.toInt()?.let { value -> value <= 0 } != false) { + error("The tile height must be greater than 0") + } + + null + } + } + } + field("Rows") { spinner(min = 1, max = 100, property = mapBuilderVM.rowsProperty, editable = true) { required() @@ -60,5 +97,25 @@ class MapCreationBasicDataView : View("Basic Data") { } } } + + buttonbar { + button("Create") { + action { + if (mapBuilderVM.commit()) { + onCompleteConsumer?.let { it(mapBuilderVM.item) } + close() + } + } + } + + button("Reset") { + action { mapBuilderVM.rollback() } + } + + + button("Cancel") { + action { close() } + } + } } } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapCreationWizard.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapCreationWizard.kt deleted file mode 100644 index 675a2909..00000000 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapCreationWizard.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.bartlomiejpluta.base.editor.map.view.wizard - -import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM -import org.kordamp.ikonli.javafx.FontIcon -import tornadofx.Wizard - -class MapCreationWizard : Wizard("New Map", "Provide map information") { - private val mapBuilderVM = find() - - init { - graphic = FontIcon("fa-map").apply { - iconSize = 40 - } - - add(MapCreationBasicDataView::class) - add(MapTileSetSelectionView::class) - } -} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapImportBasicDataView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapImportFragment.kt similarity index 73% rename from editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapImportBasicDataView.kt rename to editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapImportFragment.kt index 887be971..c9fb1421 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapImportBasicDataView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapImportFragment.kt @@ -1,13 +1,18 @@ package com.bartlomiejpluta.base.editor.map.view.wizard +import com.bartlomiejpluta.base.editor.map.model.map.GameMapBuilder import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM -import javafx.beans.binding.Bindings import javafx.stage.FileChooser import tornadofx.* import java.io.File -class MapImportBasicDataView : View("Basic Data") { +class MapImportFragment : Fragment("Basic Data") { private val mapBuilderVM = find() + private var onCompleteConsumer: ((GameMapBuilder) -> Unit)? = null + + fun onComplete(consumer: (GameMapBuilder) -> Unit) { + this.onCompleteConsumer = consumer + } override val complete = mapBuilderVM.valid( mapBuilderVM.fileProperty, @@ -61,5 +66,25 @@ class MapImportBasicDataView : View("Basic Data") { } } } + + buttonbar { + button("Create") { + action { + if (mapBuilderVM.commit()) { + onCompleteConsumer?.let { it(mapBuilderVM.item) } + close() + } + } + } + + button("Reset") { + action { mapBuilderVM.rollback() } + } + + + button("Cancel") { + action { close() } + } + } } } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapImportWizard.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapImportWizard.kt deleted file mode 100644 index addb5817..00000000 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapImportWizard.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.bartlomiejpluta.base.editor.map.view.wizard - -import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM -import org.kordamp.ikonli.javafx.FontIcon -import tornadofx.Wizard - -class MapImportWizard : Wizard("Import Map", "Provide map information") { - private val mapBuilderVM = find() - - init { - graphic = FontIcon("fa-map").apply { - iconSize = 40 - } - - add(MapImportBasicDataView::class) - add(MapTileSetSelectionView::class) - } -} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapTileSetSelectionView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapTileSetSelectionView.kt deleted file mode 100644 index 066ed01b..00000000 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/view/wizard/MapTileSetSelectionView.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.bartlomiejpluta.base.editor.map.view.wizard - -import com.bartlomiejpluta.base.editor.asset.view.select.SelectGraphicAssetView -import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM -import com.bartlomiejpluta.base.editor.project.context.ProjectContext -import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset -import tornadofx.View - -class MapTileSetSelectionView : View("Tile Set") { - private val mapBuilderVM = find() - - private val projectContext: ProjectContext by di() - - private val selectGraphicAssetView = find>( - SelectGraphicAssetView::assets to projectContext.project!!.tileSets, - SelectGraphicAssetView::asset to mapBuilderVM.tileSetAssetProperty - ) - - // FIXME - // It's kind of ugly solution because for some reason - // the custom validator on tileSetsListView does not work here. - // Desired solution should use mapBuilderVM.valid(mapBuilderVM.tileSetProperty) - // as in the previous step of the wizard as well as the feedback for user - // saying, that tile set field is required. - override val complete = mapBuilderVM.tileSetAssetProperty.isNotNull - - override val root = selectGraphicAssetView.root -} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapBuilderVM.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapBuilderVM.kt index 159bd7c7..99de21b9 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapBuilderVM.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapBuilderVM.kt @@ -6,12 +6,15 @@ import tornadofx.getValue import tornadofx.setValue class GameMapBuilderVM : ItemViewModel(GameMapBuilder()) { - val tileSetAssetProperty = bind(GameMapBuilder::tileSetAssetProperty, autocommit = true) - var tileSetAsset by tileSetAssetProperty - val nameProperty = bind(GameMapBuilder::nameProperty, autocommit = true) var name by nameProperty + val tileWidthProperty = bind(GameMapBuilder::tileWidthProperty, autocommit = true) + var tileWidth by tileWidthProperty + + val tileHeightProperty = bind(GameMapBuilder::tileHeightProperty, autocommit = true) + var tileHeight by tileHeightProperty + val rowsProperty = bind(GameMapBuilder::rowsProperty, autocommit = true) var rows by rowsProperty diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapVM.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapVM.kt index 03a1e6b9..8e2f8948 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapVM.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/viewmodel/GameMapVM.kt @@ -13,9 +13,6 @@ class GameMapVM(map: GameMap) : ItemViewModel(map) { val uidProperty = bind(GameMap::uidProperty) val uid by uidProperty - val tileSetProperty = bind(GameMap::tileSet) - val tileSet by tileSetProperty - val rowsProperty = bind(GameMap::rowsProperty) var rows by rowsProperty diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt index 2bffe850..da69a4d3 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt @@ -123,9 +123,14 @@ class DefaultProjectContext : ProjectContext { } } - override fun importMapFromFile(name: String, handler: String, file: File, tileSet: TileSet) = + override fun importMapFromFile( + name: String, + handler: String, + file: File, + replaceTileSet: (String, String) -> String + ) = project?.let { project -> - val map = file.inputStream().use { mapDeserializer.deserialize(it, tileSet) } + val map = file.inputStream().use { mapDeserializer.deserialize(it, replaceTileSet) } UID.next(project.maps.map(Asset::uid)).let { uid -> val asset = GameMapAsset(project, uid, name) map.uid = uid @@ -183,6 +188,11 @@ class DefaultProjectContext : ProjectContext { } ?: throw IllegalStateException("There is no open project in the context") } + override fun findTileSetAsset(uid: String) = project?.let { + it.tileSets.firstOrNull { tileSets -> tileSets.uid == uid } + ?: throw IllegalStateException("The Tile Set with uid [$uid] does not exist ") + } ?: throw IllegalStateException("There is no open project in the context") + override fun importImage(data: ImageAssetData) { project?.let { UID.next(it.images.map(Asset::uid)).let { uid -> diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt index 082cfb4e..8ac9bd69 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt @@ -14,6 +14,7 @@ import com.bartlomiejpluta.base.editor.image.asset.ImageAsset import com.bartlomiejpluta.base.editor.image.asset.ImageAssetData import com.bartlomiejpluta.base.editor.map.model.map.GameMap import com.bartlomiejpluta.base.editor.project.model.Project +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAssetData import com.bartlomiejpluta.base.editor.tileset.model.TileSet import javafx.beans.property.ObjectProperty @@ -29,15 +30,17 @@ interface ProjectContext { fun createNewProject(project: Project) fun importMap(name: String, map: GameMap) - fun importMapFromFile(name: String, handler: String, file: File, tileSet: TileSet): GameMap + fun importMapFromFile(name: String, handler: String, file: File, replaceTileSet: (String, String) -> String): GameMap fun loadMap(uid: String): GameMap fun saveMap(map: GameMap) fun importTileSet(data: TileSetAssetData) fun loadTileSet(uid: String): TileSet + fun findTileSetAsset(uid: String): TileSetAsset fun importImage(data: ImageAssetData) fun findImageAsset(uid: String): ImageAsset + fun loadImage(uid: String): Image fun importCharacterSet(data: CharacterSetAssetData) @@ -49,7 +52,6 @@ interface ProjectContext { fun importFont(data: FontAssetData) fun createWidget(data: WidgetAssetData): WidgetAsset - fun importSound(data: SoundAssetData) fun deleteAsset(asset: Asset) fun loadScript(fileNode: FileNode, execute: ((String) -> Unit)?, saveable: Boolean): Code diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEvent.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEvent.kt index eb5a07eb..51e2cc33 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEvent.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/render/input/MapMouseEvent.kt @@ -1,6 +1,6 @@ package com.bartlomiejpluta.base.editor.render.input -import com.bartlomiejpluta.base.editor.tileset.model.TileSet +import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM import javafx.scene.input.MouseEvent class MapMouseEvent(val row: Int, val column: Int, val event: MouseEvent) { @@ -8,9 +8,9 @@ class MapMouseEvent(val row: Int, val column: Int, val event: MouseEvent) { val button = event.button companion object { - fun of(event: MouseEvent, tileSet: TileSet) = MapMouseEvent( - (event.y / tileSet.tileHeight).toInt(), - (event.x / tileSet.tileWidth).toInt(), + fun of(event: MouseEvent, mapVM: GameMapVM) = MapMouseEvent( + (event.y / mapVM.tileHeight).toInt(), + (event.x / mapVM.tileWidth).toInt(), event ) } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt index 8c4ca5d9..00d42741 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetCanvas.kt @@ -1,38 +1,108 @@ package com.bartlomiejpluta.base.editor.tileset.canvas +import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer +import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM 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 com.bartlomiejpluta.base.editor.tileset.model.TileSet import javafx.scene.canvas.GraphicsContext +import javafx.scene.image.WritableImage import javafx.scene.input.MouseButton import javafx.scene.input.MouseEvent import javafx.scene.paint.Color +import kotlin.math.roundToInt -class TileSetCanvas(private val gameMapVM: GameMapVM, private val selection: TileSetSelection) : Renderable, MapMouseEventHandler { +class TileSetCanvas(private val editorStateVM: EditorStateVM, 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) + if (editorStateVM.selectedLayer is TileLayer) { + val tileSet = (editorStateVM.selectedLayer as TileLayer).tileSetProperty.value + renderBackground(gc) + renderTiles(gc, tileSet) + renderGrid(gc, tileSet) + 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() - ) + private fun renderBackground(gc: GraphicsContext) { + for (x in 0 until (gc.canvas.width / BACKGROUND_TILE_WIDTH).roundToInt()) { + for (y in 0 until (gc.canvas.height / BACKGROUND_TILE_HEIGHT).roundToInt()) { + gc.fill = when ((x + y) % 2) { + 0 -> BACKGROUND_COLOR1 + else -> BACKGROUND_COLOR2 + } + + gc.fillRect(x * BACKGROUND_TILE_WIDTH, y * BACKGROUND_TILE_HEIGHT, BACKGROUND_TILE_WIDTH, BACKGROUND_TILE_HEIGHT) + } + } + } + + private fun renderTiles(gc: GraphicsContext, tileSet: TileSet) { + tileSet.forEach { row, column, tile -> gc.drawImage(tile.image, column * tile.image.width, row * tile.image.height) } } + private fun renderGrid(gc: GraphicsContext, tileSet: TileSet) { + gc.stroke = Color.BLACK + gc.lineWidth = 0.5 + + for (x in 0 until (gc.canvas.width / tileSet.tileWidth).roundToInt()) { + gc.strokeLine(x.toDouble() * tileSet.tileWidth, 0.0, x.toDouble() * tileSet.tileWidth, gc.canvas.height) + } + + for (y in 0 until (gc.canvas.height / tileSet.tileHeight).roundToInt()) { + gc.strokeLine(0.0, y.toDouble() * tileSet.tileHeight, gc.canvas.width, y.toDouble() * tileSet.tileHeight) + } + + val w = gc.canvas.width - 1 + val h = gc.canvas.height - 1 + + gc.strokeLine(0.0, 0.0, w, 0.0) + gc.strokeLine(w, 0.0, w, h) + gc.strokeLine(0.0, h, w, h) + gc.strokeLine(0.0, 0.0, 0.0, h) + } + +// private fun createGrid(gc: GraphicsContext, chunkWidth: Int, chunkHeight: Int): WritableImage { +// val grid = WritableImage(gc.canvas.width.toInt(), gc.canvas.height.toInt()) +// +// val writer = grid.pixelWriter +// val color = Color.BLACK +// for (x in 0 until grid.width.toInt()) { +// for (y in 0 until grid.height.toInt()) { +// if (x % chunkWidth == 0) { +// writer.setColor(x, y, color) +// } +// +// if (y % chunkHeight == 0) { +// writer.setColor(x, y, color) +// } +// } +// } +// +// val lastX = grid.width.toInt() - 1 +// val lastY = grid.height.toInt() - 1 +// +// for (x in 0 until grid.width.toInt()) { +// writer.setColor(x, 0, color) +// writer.setColor(x, lastY, color) +// } +// +// for (y in 0 until grid.height.toInt()) { +// writer.setColor(0, y, color) +// writer.setColor(lastX, y, color) +// } +// +// return grid +// } + override fun handleMouseInput(event: MapMouseEvent) { mouseRow = event.row mouseColumn = event.column @@ -63,7 +133,9 @@ class TileSetCanvas(private val gameMapVM: GameMapVM, private val selection: Til } companion object { + private const val BACKGROUND_TILE_WIDTH = 5.0 + private const val BACKGROUND_TILE_HEIGHT = 5.0 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) + private val BACKGROUND_COLOR2 = Color.color(0.95, 0.95, 0.95, 1.0) } } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetSelection.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetSelection.kt index f66d5262..7bf7ad46 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetSelection.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/canvas/TileSetSelection.kt @@ -1,8 +1,10 @@ package com.bartlomiejpluta.base.editor.tileset.canvas import com.bartlomiejpluta.base.editor.map.model.brush.Brush +import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer 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.paint.Color @@ -10,15 +12,15 @@ import kotlin.math.abs import kotlin.math.min -class TileSetSelection(private val gameMapVM: GameMapVM, private val brushVM: BrushVM) : Renderable { +class TileSetSelection(private val editorStateVM: EditorStateVM, 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() + private var width = gameMapVM.tileWidth.toDouble() + private var height = gameMapVM.tileHeight.toDouble() fun begin(row: Double, column: Double) { @@ -31,10 +33,10 @@ class TileSetSelection(private val gameMapVM: GameMapVM, private val brushVM: Br } 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 + x = min(column, startColumn) * gameMapVM.tileWidth + y = min(row, startRow) * gameMapVM.tileHeight + width = (offsetColumn + 1) * gameMapVM.tileWidth + height = (offsetRow + 1) * gameMapVM.tileHeight } fun proceed(row: Double, column: Double) { @@ -55,14 +57,17 @@ class TileSetSelection(private val gameMapVM: GameMapVM, private val brushVM: Br 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) + if (editorStateVM.selectedLayer is TileLayer) { + val tileSet = (editorStateVM.selectedLayer as TileLayer).tileSetProperty.value + val brushArray = Array(rows) { rowIndex -> + Array(columns) { columnIndex -> + tileSet.getTile(firstRow + rowIndex, firstColumn + columnIndex) + } } - } - brushVM.item = Brush.of(brushArray) - brushVM.commit() + brushVM.item = Brush.of(brushArray) + brushVM.commit() + } } override fun render(gc: GraphicsContext) { diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/component/TileSetPane.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/component/TileSetPane.kt index ff5b1c37..3c575320 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/component/TileSetPane.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/component/TileSetPane.kt @@ -1,17 +1,22 @@ package com.bartlomiejpluta.base.editor.tileset.component +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.BrushVM +import com.bartlomiejpluta.base.editor.map.viewmodel.EditorStateVM +import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM 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 +import tornadofx.doubleBinding -class TileSetPane(private val gameMapVM: GameMapVM, brushVM: BrushVM) : Canvas(), EventHandler { - private val selection = TileSetSelection(gameMapVM, brushVM) - private val tileSetCanvas = TileSetCanvas(gameMapVM, selection) +class TileSetPane(editorStateVM: EditorStateVM, private val gameMapVM: GameMapVM, brushVM: BrushVM) : Canvas(), + EventHandler { + private val selection = TileSetSelection(editorStateVM, gameMapVM, brushVM) + private val tileSetCanvas = TileSetCanvas(editorStateVM, selection) init { onMouseMoved = this @@ -19,22 +24,37 @@ class TileSetPane(private val gameMapVM: GameMapVM, brushVM: BrushVM) : Canvas() onMousePressed = this onMouseReleased = this - width = gameMapVM.tileSet.width.toDouble() - height = gameMapVM.tileSet.height.toDouble() + updateSize(editorStateVM.selectedLayer) + editorStateVM.selectedLayerProperty.addListener { _, _, layer -> + updateSize(layer) + } brushVM.itemProperty.addListener { _, _, _ -> render() } render() } + private fun updateSize(layer: Layer?) { + if (layer is TileLayer) { + val tileSet = layer.tileSetProperty.value + width = tileSet.width.toDouble() + height = tileSet.height.toDouble() + } else { + width = 0.0 + height = 0.0 + } + + render() + } + private fun render() { tileSetCanvas.render(graphicsContext2D) } override fun handle(event: MouseEvent?) { if (event != null) { - tileSetCanvas.handleMouseInput(MapMouseEvent.of(event, gameMapVM.tileSet)) + tileSetCanvas.handleMouseInput(MapMouseEvent.of(event, gameMapVM)) } tileSetCanvas.render(graphicsContext2D) diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/editor/TileSetView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/editor/TileSetView.kt index 6bd357a5..6cc1d3ac 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/editor/TileSetView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/tileset/view/editor/TileSetView.kt @@ -1,6 +1,7 @@ package com.bartlomiejpluta.base.editor.tileset.view.editor 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 com.bartlomiejpluta.base.editor.tileset.component.TileSetPane import tornadofx.View @@ -10,8 +11,9 @@ import tornadofx.scrollpane class TileSetView : View() { private val gameMapVM = find() private val brushVM = find() + private val editorStateVM = find() - private val tileSetPane = TileSetPane(gameMapVM, brushVM) + private val tileSetPane = TileSetPane(editorStateVM, gameMapVM, brushVM) override val root = scrollpane { this += tileSetPane