[Editor] Improve select graphic asset dialog
This commit is contained in:
@@ -4,128 +4,43 @@ import com.bartlomiejpluta.base.editor.asset.viewmodel.GraphicAssetVM
|
|||||||
import javafx.beans.binding.Bindings
|
import javafx.beans.binding.Bindings
|
||||||
import javafx.beans.property.SimpleIntegerProperty
|
import javafx.beans.property.SimpleIntegerProperty
|
||||||
import javafx.scene.image.Image
|
import javafx.scene.image.Image
|
||||||
import javafx.scene.image.WritableImage
|
|
||||||
import javafx.scene.input.MouseEvent
|
import javafx.scene.input.MouseEvent
|
||||||
import javafx.scene.paint.Color
|
|
||||||
import javafx.scene.text.TextAlignment
|
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
class GraphicAssetPreviewView : View() {
|
class GraphicAssetPreviewView : View() {
|
||||||
private val vm = find<GraphicAssetVM>()
|
private val vm = find<GraphicAssetVM>()
|
||||||
private val image = Image(vm.fileProperty.value.inputStream())
|
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 mouseColumn = SimpleIntegerProperty(0)
|
||||||
private val mouseRow = 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 {
|
override val root = borderpane {
|
||||||
center = scrollpane {
|
center = scrollpane {
|
||||||
canvas(image.width + OFFSET_X, image.height + OFFSET_Y) {
|
this += canvas
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bottom = label(
|
bottom = label(
|
||||||
if (singleChunk) Bindings.format(
|
if (canvas.singleChunk) Bindings.format(
|
||||||
"Width: %d, Height: %d",
|
"Width: %d, Height: %d",
|
||||||
image.width.toInt(),
|
image.width.toInt(),
|
||||||
image.height.toInt()
|
image.height.toInt()
|
||||||
)
|
)
|
||||||
else Bindings.format(
|
else Bindings.format(
|
||||||
"Rows: %d, Columns: %d, Chunk width: %d, Chunk height: %d, Cursor: %d, %d",
|
"Rows: %d, Columns: %d, Chunk width: %d, Chunk height: %d, Cursor: %d, %d",
|
||||||
rows,
|
canvas.rows,
|
||||||
columns,
|
canvas.columns,
|
||||||
chunkWidth,
|
canvas.chunkWidth,
|
||||||
chunkHeight,
|
canvas.chunkHeight,
|
||||||
mouseRow,
|
mouseRow,
|
||||||
mouseColumn
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package com.bartlomiejpluta.base.editor.asset.view.select
|
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.BooleanProperty
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.beans.property.StringProperty
|
import javafx.beans.property.StringProperty
|
||||||
import javafx.collections.ObservableList
|
import javafx.collections.ObservableList
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class SelectGraphicAssetFragment<T : Asset> : Fragment("Select Asset") {
|
class SelectGraphicAssetFragment<T : GraphicAsset> : Fragment("Select Asset") {
|
||||||
val assets: ObservableList<T> by param()
|
val assets: ObservableList<T> by param()
|
||||||
val cancelable: BooleanProperty by param(true.toProperty())
|
val cancelable: BooleanProperty by param(true.toProperty())
|
||||||
val comment: StringProperty by param("".toProperty())
|
val comment: StringProperty by param("".toProperty())
|
||||||
@@ -26,7 +26,7 @@ class SelectGraphicAssetFragment<T : Asset> : Fragment("Select Asset") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val root = form {
|
override val root = form {
|
||||||
if(comment.isNotEmpty.value) {
|
if (comment.isNotEmpty.value) {
|
||||||
label(comment) {
|
label(comment) {
|
||||||
visibleWhen(comment.isNotEmpty)
|
visibleWhen(comment.isNotEmpty)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package com.bartlomiejpluta.base.editor.asset.view.select
|
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.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.binding.Bindings.createObjectBinding
|
||||||
import javafx.beans.property.ObjectProperty
|
import javafx.beans.property.ObjectProperty
|
||||||
import javafx.collections.ObservableList
|
import javafx.collections.ObservableList
|
||||||
@@ -9,16 +13,22 @@ import javafx.scene.image.Image
|
|||||||
import javafx.scene.image.WritableImage
|
import javafx.scene.image.WritableImage
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class SelectGraphicAssetView<T : Asset> : View() {
|
class SelectGraphicAssetView<T : GraphicAsset> : View() {
|
||||||
val assets: ObservableList<T> by param()
|
val assets: ObservableList<T> by param()
|
||||||
val asset: ObjectProperty<T> by param()
|
val asset: ObjectProperty<T> by param()
|
||||||
|
|
||||||
|
val vm = GraphicAssetVM(null)
|
||||||
|
|
||||||
private var assetsListView: ListView<T> by singleAssign()
|
private var assetsListView: ListView<T> by singleAssign()
|
||||||
|
|
||||||
private val image = createObjectBinding({
|
private val image = createObjectBinding({
|
||||||
asset.value?.file?.inputStream()?.use { Image(it) } ?: PLACEHOLDER_IMAGE
|
asset.value?.file?.inputStream()?.use { Image(it) } ?: PLACEHOLDER_IMAGE
|
||||||
}, asset)
|
}, asset)
|
||||||
|
|
||||||
|
init {
|
||||||
|
asset.addListener { _, _, item -> vm.item = item }
|
||||||
|
}
|
||||||
|
|
||||||
override val root = hbox {
|
override val root = hbox {
|
||||||
|
|
||||||
assetsListView = listview(assets) {
|
assetsListView = listview(assets) {
|
||||||
@@ -29,7 +39,7 @@ class SelectGraphicAssetView<T : Asset> : View() {
|
|||||||
scrollpane {
|
scrollpane {
|
||||||
prefWidth = 480.0
|
prefWidth = 480.0
|
||||||
prefHeight = 480.0
|
prefHeight = 480.0
|
||||||
imageview(image)
|
this += GraphicAssetViewCanvas(vm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import com.bartlomiejpluta.base.editor.asset.model.GraphicAsset
|
|||||||
import javafx.beans.property.SimpleIntegerProperty
|
import javafx.beans.property.SimpleIntegerProperty
|
||||||
import tornadofx.ItemViewModel
|
import tornadofx.ItemViewModel
|
||||||
|
|
||||||
class GraphicAssetVM(asset: GraphicAsset) : ItemViewModel<GraphicAsset>(asset) {
|
class GraphicAssetVM(asset: GraphicAsset?) : ItemViewModel<GraphicAsset>(asset) {
|
||||||
val nameProperty = bind(GraphicAsset::nameProperty)
|
val nameProperty = bind(GraphicAsset::nameProperty)
|
||||||
val fileProperty = bind(GraphicAsset::file)
|
val fileProperty = bind(GraphicAsset::file)
|
||||||
val rowsProperty = bind(GraphicAsset::rowsProperty)
|
val rowsProperty = bind(GraphicAsset::rowsProperty)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.bartlomiejpluta.base.editor.common.parameter.model
|
package com.bartlomiejpluta.base.editor.common.parameter.model
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.editor.asset.model.Asset
|
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.view.select.SelectGraphicAssetFragment
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.collections.ObservableList
|
import javafx.collections.ObservableList
|
||||||
@@ -11,7 +12,7 @@ import tornadofx.Scope
|
|||||||
import tornadofx.find
|
import tornadofx.find
|
||||||
import tornadofx.select
|
import tornadofx.select
|
||||||
|
|
||||||
class GraphicAssetParameter<T : Asset>(
|
class GraphicAssetParameter<T : GraphicAsset>(
|
||||||
key: String,
|
key: String,
|
||||||
initialValue: T,
|
initialValue: T,
|
||||||
editable: Boolean = true,
|
editable: Boolean = true,
|
||||||
|
|||||||
Reference in New Issue
Block a user