package uk.co.nickthecoder.gamescupboard.client
import com.soywiz.korge.ui.UiSkinKind
import com.soywiz.korge.ui.UiSkinType
import com.soywiz.korim.bitmap.*
import com.soywiz.korim.color.Colors
import com.soywiz.korim.color.RGBA
import com.soywiz.korim.paint.Paint
import com.soywiz.korma.geom.degrees
import com.soywiz.korma.geom.vector.*
/**
* Most of this code was taken from com.soywiz.korge.ui.UISkin.
* But instead of building a single skin, we can create skins of any shape and color scheme.
*
* NOTE. UISkins uses a hard-coded value of 16 for the margins of the NinePatches.
* So you cannot use (lineWidth + radius) larger than 16.
*
* NOTE. I don't fully understand how the KorGE's UI components use this bitmap. Beware!
*/
abstract class SkinBitmapBuilder {
fun createBitmap(): Bitmap32 =
NativeImage(512, 512).context2d {
for (kind in listOf(UiSkinKind.BUTTON, UiSkinKind.RADIO)) {
for (n in 0 until 4) {
drawImage(buildButton(UiSkinType(n), kind), (kind.id * 256) + (n * 64), 0)
}
}
for (n in 0 until 5) {
for (enabled in listOf(false, true)) {
drawImage(buildShape(n, enabled), 64.0 * (if (enabled) 0 else 1), 64 + 64.0 * n)
}
}
}.mipmaps(true).toBMP32IfRequired()
abstract fun buildShape(index: Int, enabled: Boolean): Bitmap
abstract fun buildButton(index: UiSkinType, kind: UiSkinKind): Bitmap
}
class CustomisableSkinBitmapBuilder(
val lineWidth: Int = 4,
val radius: Int = 6,
// For buildDefaultShape.
val shapedEnabled: RGBA,
val shapedDisabled: RGBA,
// For buildDefaultButton
val normal: RGBA,
val over: RGBA,
val down: RGBA,
val disabled: RGBA,
val borderNormal: RGBA,
val borderOver: RGBA,
val borderDown: RGBA,
val borderDisabled: RGBA,
/**
* I have no clue what this is for! I've kept it here for consistency with the code from UISkins.
* For some reason, when building buttons, UISkins uses an index of 5, which
* is outside the range 0..4 of [UiSkinType]. Hmm.
*/
val fifthType: RGBA = Colors["#3c3e3e"]
) : SkinBitmapBuilder() {
override fun buildShape(index: Int, enabled: Boolean): Bitmap {
val color = com.soywiz.korim.paint.ColorPaint(if (enabled) this.shapedEnabled else shapedDisabled)
val lineWidth = this@CustomisableSkinBitmapBuilder.lineWidth.toDouble()
return NativeImage(64, 64).context2d {
when (index) {
0 -> {
translate(27, 41)
rotate(45.degrees)
stroke(color, lineWidth = lineWidth, lineCap = LineCap.BUTT) {
moveTo(-16, 0)
lineTo(0, 0)
lineTo(0, -32)
}
}
else -> {
translate(32, 32)
rotate((45 + 90 * (index - 1)).degrees)
val offsetX = -8
val offsetY = -8
val lineLength = 20
stroke(color, lineWidth = lineWidth, lineCap = LineCap.SQUARE) {
line(offsetX + 0, offsetY + 0, offsetX + 0, offsetY + lineLength)
line(offsetX + 0, offsetY + 0, offsetX + lineLength, offsetY + 0)
}
}
}
}
}
override fun buildButton(index: UiSkinType, kind: UiSkinKind): Bitmap {
val doubleLineWidth = this.lineWidth * 2
val lineWidth = this.lineWidth
return NativeImage(64, 64).context2d {
val fill: Paint = when (index) {
UiSkinType.NORMAL -> normal
UiSkinType.OVER -> over
UiSkinType.DOWN -> down
UiSkinType.DISABLED -> disabled
// NOTE, in to original, there was an error thrown. Don't do this!
// I think it is never used, and was only there because UiSkinType is not an enum.
else -> fifthType
}
val border: Paint = when (index) {
UiSkinType.NORMAL -> borderNormal
UiSkinType.OVER -> borderOver
UiSkinType.DOWN -> borderDown
UiSkinType.DISABLED -> borderDisabled
// I have no clue what this fifth type is used for. My guss is, it isn't!
else -> fifthType
}
fill(fill) {
stroke(border, lineWidth = doubleLineWidth.toDouble()) {
when (kind) {
UiSkinKind.RADIO -> circle(32.0, 32.0, 28.0)
UiSkinKind.BUTTON -> roundRect(
lineWidth, lineWidth,
64 - doubleLineWidth, 64 - doubleLineWidth,
radius, radius
)
}
}
}
}
}
}