diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/GraphicAssetPreviewView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/GraphicAssetPreviewView.kt index 3b00a252..e6c9e766 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/GraphicAssetPreviewView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/GraphicAssetPreviewView.kt @@ -4,128 +4,43 @@ import com.bartlomiejpluta.base.editor.asset.viewmodel.GraphicAssetVM import javafx.beans.binding.Bindings import javafx.beans.property.SimpleIntegerProperty import javafx.scene.image.Image -import javafx.scene.image.WritableImage import javafx.scene.input.MouseEvent -import javafx.scene.paint.Color -import javafx.scene.text.TextAlignment import tornadofx.* import kotlin.math.max class GraphicAssetPreviewView : View() { private val vm = find() private val image = Image(vm.fileProperty.value.inputStream()) - private val rows = vm.rowsProperty.value - private val columns = vm.columnsProperty.value - private val chunkWidth = (image.width / columns).toInt() - private val chunkHeight = (image.height / rows).toInt() private val mouseColumn = SimpleIntegerProperty(0) private val mouseRow = SimpleIntegerProperty(0) - private val singleChunk = rows == 1 && columns == 1 + + private val canvas = GraphicAssetViewCanvas(vm).apply { + addEventHandler(MouseEvent.ANY) { + mouseColumn.value = max(0, (it.x / this.chunkWidth).toInt() - 1) + mouseRow.value = max(0, (it.y / this.chunkHeight).toInt() - 1) + } + } override val root = borderpane { center = scrollpane { - canvas(image.width + OFFSET_X, image.height + OFFSET_Y) { - addEventHandler(MouseEvent.ANY) { - mouseColumn.value = max(0, (it.x / chunkWidth).toInt() - 1) - mouseRow.value = max(0, (it.y / chunkHeight).toInt() - 1) - } - - graphicsContext2D.drawImage(createBackgroundImage(), OFFSET_X, OFFSET_Y) - graphicsContext2D.drawImage(image, OFFSET_X, OFFSET_Y) - - if(!singleChunk) { - graphicsContext2D.textAlign = TextAlignment.LEFT - for (i in 0 until columns) { - graphicsContext2D.fillText(i.toString(), OFFSET_X + chunkWidth * i + INDEX_OFFSET_X, OFFSET_Y - 5.0) - } - - graphicsContext2D.textAlign = TextAlignment.RIGHT - for (i in 0 until rows) { - graphicsContext2D.fillText(i.toString(), OFFSET_X - 5.0, OFFSET_Y + chunkHeight * i + INDEX_OFFSET_Y) - } - } - - if(!singleChunk) graphicsContext2D.drawImage(createGrid(), OFFSET_X, OFFSET_Y) - } + this += canvas } bottom = label( - if (singleChunk) Bindings.format( + if (canvas.singleChunk) Bindings.format( "Width: %d, Height: %d", image.width.toInt(), image.height.toInt() ) else Bindings.format( "Rows: %d, Columns: %d, Chunk width: %d, Chunk height: %d, Cursor: %d, %d", - rows, - columns, - chunkWidth, - chunkHeight, + canvas.rows, + canvas.columns, + canvas.chunkWidth, + canvas.chunkHeight, mouseRow, mouseColumn ) ) } - - private fun createBackgroundImage(): WritableImage { - val background = WritableImage(image.width.toInt(), image.height.toInt()) - - val writer = background.pixelWriter - for (x in 0 until background.width.toInt()) { - for (y in 0 until background.height.toInt()) { - val color = when (((x / BACKGROUND_TILE_WIDTH) + (y / BACKGROUND_TILE_HEIGHT)) % 2) { - 0 -> BACKGROUND_COLOR1 - else -> BACKGROUND_COLOR2 - } - - writer.setColor(x, y, color) - } - } - - return background - } - - private fun createGrid(): WritableImage { - val grid = WritableImage(image.width.toInt(), image.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 - } - - companion object { - private const val BACKGROUND_TILE_WIDTH = 5 - private const val BACKGROUND_TILE_HEIGHT = 5 - 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, 1.0) - private const val OFFSET_X = 30.0 - private const val OFFSET_Y = 30.0 - private const val INDEX_OFFSET_X = 0.0 - private const val INDEX_OFFSET_Y = 10.0 - } } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/GraphicAssetViewCanvas.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/GraphicAssetViewCanvas.kt new file mode 100644 index 00000000..285c8627 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/component/GraphicAssetViewCanvas.kt @@ -0,0 +1,131 @@ +package com.bartlomiejpluta.base.editor.asset.component + +import com.bartlomiejpluta.base.editor.asset.model.GraphicAsset +import com.bartlomiejpluta.base.editor.asset.viewmodel.GraphicAssetVM +import javafx.scene.canvas.Canvas +import javafx.scene.image.Image +import javafx.scene.image.WritableImage +import javafx.scene.paint.Color +import javafx.scene.text.TextAlignment +import tornadofx.getValue + +class GraphicAssetViewCanvas(asset: GraphicAssetVM) : Canvas() { + private var image: Image? = null + + val rows by asset.rowsProperty + val columns by asset.columnsProperty + + var chunkWidth: Int = 1// = //(image.width / columns).toInt() + private set + + var chunkHeight: Int = 1// = (image.height / rows).toInt() + private set + + var singleChunk = rows == 1 && columns == 1 + private set + + init { + asset.itemProperty.addListener { _, _, item -> updateAsset(item) } + updateAsset(asset.item) + } + + private fun updateAsset(asset: GraphicAsset?) { + asset?.let { + image = Image(it.file.inputStream()) + width = image!!.width + OFFSET_X + height = image!!.height + OFFSET_Y + chunkWidth = (image!!.width / columns).toInt() + chunkHeight = (image!!.height / rows).toInt() + singleChunk = rows == 1 && columns == 1 + } + + render() + } + + fun render() { + graphicsContext2D.clearRect(0.0, 0.0, width, height) + + if (image == null) { + return + } + + graphicsContext2D.drawImage(createBackgroundImage(), OFFSET_X, OFFSET_Y) + graphicsContext2D.drawImage(image, OFFSET_X, OFFSET_Y) + + if (!singleChunk) { + graphicsContext2D.textAlign = TextAlignment.LEFT + for (i in 0 until columns) { + graphicsContext2D.fillText(i.toString(), OFFSET_X + chunkWidth * i + INDEX_OFFSET_X, OFFSET_Y - 5.0) + } + + graphicsContext2D.textAlign = TextAlignment.RIGHT + for (i in 0 until rows) { + graphicsContext2D.fillText(i.toString(), OFFSET_X - 5.0, OFFSET_Y + chunkHeight * i + INDEX_OFFSET_Y) + } + } + + if (!singleChunk) graphicsContext2D.drawImage(createGrid(), OFFSET_X, OFFSET_Y) + } + + private fun createBackgroundImage(): WritableImage { + val background = WritableImage(image!!.width.toInt(), image!!.height.toInt()) + + val writer = background.pixelWriter + for (x in 0 until background.width.toInt()) { + for (y in 0 until background.height.toInt()) { + val color = when (((x / BACKGROUND_TILE_WIDTH) + (y / BACKGROUND_TILE_HEIGHT)) % 2) { + 0 -> BACKGROUND_COLOR1 + else -> BACKGROUND_COLOR2 + } + + writer.setColor(x, y, color) + } + } + + return background + } + + private fun createGrid(): WritableImage { + val grid = WritableImage(image!!.width.toInt(), image!!.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 + } + + companion object { + private const val BACKGROUND_TILE_WIDTH = 5 + private const val BACKGROUND_TILE_HEIGHT = 5 + 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, 1.0) + private const val OFFSET_X = 30.0 + private const val OFFSET_Y = 30.0 + private const val INDEX_OFFSET_X = 0.0 + private const val INDEX_OFFSET_Y = 10.0 + } +} \ No newline at end of file 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 f028b217..e3e5e36d 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,13 +1,13 @@ package com.bartlomiejpluta.base.editor.asset.view.select -import com.bartlomiejpluta.base.editor.asset.model.Asset +import com.bartlomiejpluta.base.editor.asset.model.GraphicAsset 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") { +class SelectGraphicAssetFragment : Fragment("Select Asset") { val assets: ObservableList by param() val cancelable: BooleanProperty by param(true.toProperty()) val comment: StringProperty by param("".toProperty()) @@ -26,7 +26,7 @@ class SelectGraphicAssetFragment : Fragment("Select Asset") { } override val root = form { - if(comment.isNotEmpty.value) { + if (comment.isNotEmpty.value) { label(comment) { visibleWhen(comment.isNotEmpty) } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/select/SelectGraphicAssetView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/select/SelectGraphicAssetView.kt index 2919cfc2..cca188e2 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/select/SelectGraphicAssetView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/view/select/SelectGraphicAssetView.kt @@ -1,6 +1,10 @@ package com.bartlomiejpluta.base.editor.asset.view.select +import com.bartlomiejpluta.base.editor.asset.component.GraphicAssetPreviewView +import com.bartlomiejpluta.base.editor.asset.component.GraphicAssetViewCanvas import com.bartlomiejpluta.base.editor.asset.model.Asset +import com.bartlomiejpluta.base.editor.asset.model.GraphicAsset +import com.bartlomiejpluta.base.editor.asset.viewmodel.GraphicAssetVM import javafx.beans.binding.Bindings.createObjectBinding import javafx.beans.property.ObjectProperty import javafx.collections.ObservableList @@ -9,16 +13,22 @@ import javafx.scene.image.Image import javafx.scene.image.WritableImage import tornadofx.* -class SelectGraphicAssetView : View() { +class SelectGraphicAssetView : View() { val assets: ObservableList by param() val asset: ObjectProperty by param() + val vm = GraphicAssetVM(null) + private var assetsListView: ListView by singleAssign() private val image = createObjectBinding({ asset.value?.file?.inputStream()?.use { Image(it) } ?: PLACEHOLDER_IMAGE }, asset) + init { + asset.addListener { _, _, item -> vm.item = item } + } + override val root = hbox { assetsListView = listview(assets) { @@ -29,7 +39,7 @@ class SelectGraphicAssetView : View() { scrollpane { prefWidth = 480.0 prefHeight = 480.0 - imageview(image) + this += GraphicAssetViewCanvas(vm) } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/viewmodel/GraphicAssetVM.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/viewmodel/GraphicAssetVM.kt index 87af0e3f..558fb1f5 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/viewmodel/GraphicAssetVM.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/asset/viewmodel/GraphicAssetVM.kt @@ -4,7 +4,7 @@ import com.bartlomiejpluta.base.editor.asset.model.GraphicAsset import javafx.beans.property.SimpleIntegerProperty import tornadofx.ItemViewModel -class GraphicAssetVM(asset: GraphicAsset) : ItemViewModel(asset) { +class GraphicAssetVM(asset: GraphicAsset?) : ItemViewModel(asset) { val nameProperty = bind(GraphicAsset::nameProperty) val fileProperty = bind(GraphicAsset::file) val rowsProperty = bind(GraphicAsset::rowsProperty) diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/parameter/model/GraphicAssetParameter.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/parameter/model/GraphicAssetParameter.kt index 1b5db7a4..149f8b0a 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/parameter/model/GraphicAssetParameter.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/parameter/model/GraphicAssetParameter.kt @@ -1,6 +1,7 @@ package com.bartlomiejpluta.base.editor.common.parameter.model 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 javafx.beans.property.SimpleObjectProperty import javafx.collections.ObservableList @@ -11,7 +12,7 @@ import tornadofx.Scope import tornadofx.find import tornadofx.select -class GraphicAssetParameter( +class GraphicAssetParameter( key: String, initialValue: T, editable: Boolean = true,