Updated KorGE to 1.5.0c

This commit is contained in:
soywiz
2019-12-12 19:56:11 +01:00
parent 46508f35f3
commit 0c769d8016
18 changed files with 53 additions and 755 deletions

View File

@@ -6,6 +6,6 @@ buildscript {
mavenCentral()
}
dependencies {
classpath("com.soywiz.korlibs.korge.plugins:korge-gradle-plugin:1.4.3c")
classpath("com.soywiz.korlibs.korge.plugins:korge-gradle-plugin:$korgePluginVersion")
}
}

View File

@@ -1,3 +1,6 @@
korgePluginVersion=1.5.0c
org.gradle.jvmargs=-Xmx1536m
org.gradle.parallel=true
#disable.kotlin.native=true
org.gradle.parallel.intra=true
org.gradle.configureondemand=true

View File

@@ -5,9 +5,9 @@ import com.soywiz.korge.render.*
import com.soywiz.korge.scene.*
import com.soywiz.korge.tween.*
import com.soywiz.korge.view.*
import com.soywiz.korge3d.experimental.*
import com.soywiz.korge3d.experimental.animation.*
import com.soywiz.korge3d.experimental.format.*
import com.soywiz.korge3d.*
import com.soywiz.korge3d.animation.*
import com.soywiz.korge3d.format.*
import com.soywiz.korim.color.*
import com.soywiz.korim.format.*
import com.soywiz.korinject.*

View File

@@ -3,7 +3,7 @@ import com.soywiz.korge.input.*
import com.soywiz.korge.scene.*
import com.soywiz.korge.tween.*
import com.soywiz.korge.view.*
import com.soywiz.korge3d.experimental.*
import com.soywiz.korge3d.*
import com.soywiz.korim.color.*
import com.soywiz.korio.async.*
import com.soywiz.korma.geom.*

View File

@@ -19,9 +19,9 @@ class AtlasTest : ViewsForTesting() {
fun testAtlas() = suspendTest {
val atlas = resourcesVfs["logos.atlas.json"].readAtlas(views)
assertEquals(3, atlas.textures.size)
assertEquals(Size(66, 66), atlas.textures["korau.png"]!!.texture.size)
assertEquals(Size(66, 66), atlas.textures["korge.png"]!!.texture.size)
assertEquals(Size(66, 66), atlas.textures["korim.png"]!!.texture.size)
assertEquals(Size(64, 64), atlas.textures["korau.png"]!!.texture.size)
assertEquals(Size(64, 64), atlas.textures["korge.png"]!!.texture.size)
assertEquals(Size(64, 64), atlas.textures["korim.png"]!!.texture.size)
}
private val BmpSlice.size get() = Size(width, height)

View File

@@ -1,106 +1,66 @@
import com.soywiz.korge.*
import com.soywiz.korge.admob.*
import com.soywiz.korge.box2d.*
import com.soywiz.korge.input.*
import com.soywiz.korge.view.*
import com.soywiz.korgw.*
import com.soywiz.korim.color.*
import com.soywiz.korim.format.*
import com.soywiz.korim.vector.*
import com.soywiz.korio.async.*
import com.soywiz.korio.file.std.*
import com.soywiz.korio.lang.*
import com.soywiz.korma.geom.vector.*
import org.jbox2d.collision.shapes.*
import org.jbox2d.callbacks.*
import org.jbox2d.collision.*
import org.jbox2d.dynamics.*
import org.jbox2d.dynamics.contacts.*
suspend fun main() = Korge(quality = GameWindow.Quality.PERFORMANCE, title = "My Awesome Box2D Game!") {
val admob = AdmobCreate(testing = true)
println("STARTED!")
addUpdatable {
//println("FRAME!")
}
launchImmediately {
try {
admob.bannerPrepareAndShow(Admob.Config("ca-app-pub-xxx/xxx"))
} catch (e: Throwable) {
e.printStackTrace()
}
}
views.clearColor = Colors.DARKGREEN
solidRect(300, 200, Colors.DARKCYAN)
sgraphics {
fill(Colors.DARKCYAN) {
rect(-1, -1, 3, 2)
}
fill(Colors.AQUAMARINE) {
circle(0, 0, 1)
}
fill(Colors.AQUAMARINE) {
circle(1, 0, 1)
}
position(100, 100)
}.scale(100, 100).interactive()
worldView {
position(400, 400).scale(20)
createBody {
setPosition(0, -10)
}.fixture {
shape = BoxShape(100, 20)
density = 0f
}.setViewWithContainer(solidRect(100, 20, Colors.RED).position(-50, -10).interactive())
}.setView(solidRect(100, 20, Colors.RED).position(-50, -10))
// Dynamic Body
createBody {
val ball = createBody {
type = BodyType.DYNAMIC
setPosition(0, 7)
setPosition(0, 0)
}.fixture {
shape = BoxShape(2f, 2f)
density = 0.5f
friction = 0.2f
}.setView(solidRect(2f, 2f, Colors.GREEN).anchor(.5, .5).interactive())
shape = BoxShape(4f, 4f)
density = 985f
friction = 0f
userData = "ball"
}.setView(container {
// [...]
})
createBody {
val enemy = createBody {
type = BodyType.DYNAMIC
setPosition(0.75, 13)
setPosition(5, 0)
}.fixture {
shape = BoxShape(2f, 2f)
density = 1f
friction = 0.2f
}.setView(sgraphics {
fill(Colors.BLUE) {
rect(-1f, -1f, 2f, 2f)
}
}.interactive())
createBody {
type = BodyType.DYNAMIC
setPosition(0.5, 15)
}.fixture {
shape = CircleShape().apply { m_radius = 2f }
density = 22f
friction = 3f
}.setView(sgraphics {
fillStroke(Context2d.Color(Colors.BLUE), Context2d.Color(Colors.RED), Context2d.StrokeInfo(thickness = 0.3)) {
circle(0, 0, 2)
//rect(0, 0, 400, 20)
}
fill(Colors.DARKCYAN) {
circle(1, 1, 0.2)
}
hitTestUsingShapes = true
}.interactive())
shape = BoxShape(10, 20)
}.setView(container {
image(resourcesVfs["korge-ui.png"].readBitmap())
.size(4f, 4f)
.position(-2f, -2f)
})
}.apply {
world.setContactListener(contactListener)
}
image(resourcesVfs["korge.png"].readBitmap())
}
fun <T : View> T.interactive(): T = this.apply {
alpha = 0.5
onOver { alpha = 1.0 }
onOut { alpha = 0.5 }
val contactListener = object : ContactListener {
override fun beginContact(contact: Contact) {
println("beginContact")
}
override fun endContact(contact: Contact) {
println("endContact")
}
override fun postSolve(contact: Contact, impulse: ContactImpulse) {
println("postSolve")
}
override fun preSolve(contact: Contact, oldManifold: Manifold) {
println("preSolve")
}
}

View File

@@ -13,7 +13,8 @@ import com.soywiz.korio.lang.*
import com.soywiz.korma.geom.*
import com.soywiz.korma.geom.ds.*
suspend fun main() = Korge(Korge.Config(module = TicTacToeModule, debug = true))
//suspend fun main() = Korge(Korge.Config(module = TicTacToeModule, debug = true))
suspend fun main() = Korge(Korge.Config(module = TicTacToeModule))
object TicTacToeModule : Module() {
override val mainScene = TicTacToeMainScene::class

View File

@@ -1,64 +0,0 @@
package com.soywiz.korge.newui
import com.soywiz.kds.*
import com.soywiz.korge.html.*
import com.soywiz.korge.scene.*
import com.soywiz.korim.bitmap.*
import com.soywiz.korim.color.*
import com.soywiz.korim.font.*
import com.soywiz.korim.format.*
import com.soywiz.korio.util.*
import com.soywiz.korio.util.encoding.*
val DEFAULT_UI_SKIN_IMG by lazy {
PNG.decode(
"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".fromBase64()
).toBMP32()
}
val DefaultUISkin by lazy {
UISkin(
normal = DEFAULT_UI_SKIN_IMG.sliceWithSize(0, 0, 64, 64),
hover = DEFAULT_UI_SKIN_IMG.sliceWithSize(64, 0, 64, 64),
down = DEFAULT_UI_SKIN_IMG.sliceWithSize(127, 0, 64, 64),
font = Html.FontFace.Bitmap(getSyncDebugBmpFontOnce())
)
}
private class SyncOnce<T> {
var value: T? = null
operator fun invoke(callback: () -> T): T {
if (value == null) {
value = callback()
}
return value!!
}
}
private var bmpFontOnce2 = SyncOnce<BitmapFont>()
private fun getSyncDebugBmpFontOnce() = bmpFontOnce2 {
val tex = PNG.decode(DebugBitmapFont.DEBUG_FONT_BYTES).toBMP32().premultiplied().slice()
val fntAdvance = 7
val fntWidth = 8
val fntHeight = 8
val fntBlockX = 2
val fntBlockY = 2
val fntBlockWidth = 12
val fntBlockHeight = 12
BitmapFont(tex.bmp, fntHeight, fntHeight, fntHeight, (0 until 256).associate {
val x = it % 16
val y = it / 16
it to BitmapFont.Glyph(
it,
tex.sliceWithSize(x * fntBlockWidth + fntBlockX, y * fntBlockHeight + fntBlockY, fntWidth, fntHeight),
0,
0,
fntAdvance
)
}.toIntMap(), IntMap())
}

View File

@@ -1,106 +0,0 @@
package com.soywiz.korge.newui
import com.soywiz.korge.html.*
import com.soywiz.korge.input.*
import com.soywiz.korge.render.*
import com.soywiz.korge.view.*
import com.soywiz.korim.color.*
import com.soywiz.korma.geom.*
import kotlin.properties.*
inline fun Container.uiButton(
width: Number = 128,
height: Number = 64,
label: String = "Button",
skin: UISkin = defaultUISkin,
block: UIButton.() -> Unit = {}
): UIButton = UIButton(width.toDouble(), height.toDouble(), label, skin).also { addChild(it) }.apply(block)
open class UIButton(
width: Double = 128.0,
height: Double = 64.0,
label: String = "Button",
skin: UISkin = DefaultUISkin
) : UIView(width, height) {
var forcePressed by uiObservable(false) { updateState() }
var skin: UISkin by uiObservable(skin) { updateState() }
var label by uiObservable(label) { updateState() }
private val rect = ninePatch(skin.normal, width, height, 16.0 / 64.0, 16.0 / 64.0, (64.0 - 16.0) / 64.0, (64.0 - 16.0) / 64.0) {}
private val textShadow = text(label).also { it.position(1, 1) }
private val text = text(label)
private var bover by uiObservable(false) { updateState() }
private var bpressing by uiObservable(false) { updateState() }
// @TODO: Make mouseEnabled open
//override var mouseEnabled = uiObservable(true) { updateState() }
fun simulateHover() {
bover = true
}
fun simulateOut() {
bover = false
}
fun simulatePressing(value: Boolean) {
bpressing = value
}
fun simulateDown() {
bpressing = true
}
fun simulateUp() {
bpressing = false
}
init {
mouse {
onOver {
simulateHover()
}
onOut {
simulateOut()
}
onDown {
simulateDown()
}
onUpAnywhere {
simulateUp()
}
}
updateState()
}
private fun updateState() {
when {
bpressing || forcePressed -> {
rect.tex = skin.down
}
bover -> {
rect.tex = skin.hover
}
else -> {
rect.tex = skin.normal
}
}
text.format = Html.Format(face = skin.font, align = Html.Alignment.MIDDLE_CENTER, color = Colors.WHITE)
text.setTextBounds(Rectangle(0, 0, width, height))
text.setText(label)
textShadow.format = Html.Format(face = skin.font, align = Html.Alignment.MIDDLE_CENTER, color = Colors.BLACK.withA(64))
textShadow.setTextBounds(Rectangle(0, 0, width, height))
textShadow.setText(label)
}
override fun updatedSize() {
super.updatedSize()
rect.width = width
rect.height = height
updateState()
}
override fun renderInternal(ctx: RenderContext) {
//alpha = if (mouseEnabled) 1.0 else 0.5
super.renderInternal(ctx)
}
}

View File

@@ -1,59 +0,0 @@
package com.soywiz.korge.newui
import com.soywiz.korge.html.*
import com.soywiz.korge.input.*
import com.soywiz.korge.view.*
import com.soywiz.korim.color.*
import com.soywiz.korma.geom.*
import kotlin.properties.*
inline fun Container.uiCheckBox(
checked: Boolean? = false,
width: Number = 96.0,
height: Number = 32.0,
label: String = "CheckBox",
skin: UISkin = defaultUISkin,
block: UICheckBox.() -> Unit = {}
): UICheckBox = UICheckBox(checked, width.toDouble(), height.toDouble(), label, skin).also { addChild(it) }.apply(block)
open class UICheckBox(
checked: Boolean? = false,
width: Double = 96.0,
height: Double = 32.0,
label: String = "CheckBox",
private val skin: UISkin = DefaultUISkin
) : UIView(width, height) {
var checked by uiObservable(checked) { onPropsUpdate() }
var label by uiObservable(label) { onPropsUpdate() }
private val area = solidRect(16, 16, Colors.TRANSPARENT_BLACK)
//private val box = solidRect(16, 16, Colors.DARKGREY)
private val box = uiButton(16, 16, skin = skin).also { it.mouseEnabled = false }
private val text = text(label)
init {
onClick {
this@UICheckBox.checked = this@UICheckBox.checked != true
onPropsUpdate()
}
onPropsUpdate()
}
protected fun onPropsUpdate() {
println("checked: $checked")
area.position(0, 0).size(width, height)
box.position(0, 0).size(height, height)
.also {
it.forcePressed = true
if (checked == true) {
it.label = "X"
} else {
it.label = ""
}
}
text.position(height + 8.0, 0)
.also { it.format = Html.Format(face = skin.font, align = Html.Alignment.MIDDLE_LEFT) }
.also { it.setTextBounds(Rectangle(0, 0, width - height, height)) }
.setText(label)
}
}

View File

@@ -1,95 +0,0 @@
package com.soywiz.korge.newui
import com.soywiz.korge.input.*
import com.soywiz.korge.view.*
import com.soywiz.korim.color.*
import com.soywiz.korio.async.*
inline fun <T> Container.uiComboBox(
width: Number = 192.0,
height: Number = 32.0,
selectedIndex: Int = 0,
items: List<T>,
skin: UISkin = defaultUISkin,
block: UIComboBox<T>.() -> Unit = {}
) = UIComboBox(width.toDouble(), height.toDouble(), selectedIndex, items, skin).also { addChild(it) }.also(block)
open class UIComboBox<T>(
width: Double = 192.0,
height: Double = 32.0,
selectedIndex: Int = 0,
items: List<T>,
private val skin: UISkin = DefaultUISkin
) : UIView(width, height) {
val onUpdatedSelection = Signal<UIComboBox<T>>()
var selectedIndex by uiObservable(selectedIndex) { updatedSelection() }
var selectedItem: T?
set(value) = run { selectedIndex = items.indexOf(value) }
get() = items.getOrNull(selectedIndex)
var items: List<T> by uiObservable(items) { updatedItems() }
val itemHeight get() = 32
private val buttonSize get() = height
private val itemsView = uiScrollableArea(verticalScroll = true, horizontalScroll = false, skin = skin, config = { visible = false }) { }
private val selectedButton = uiButton(16, 16, "", skin = skin).also { it.mouseEnabled = false }
private val dropButton = uiButton(16, 16, "+", skin = skin).also { it.mouseEnabled = false }
private val invisibleRect = solidRect(16, 16, Colors.TRANSPARENT_BLACK)
private var showItems = false
init {
updatedItems()
invisibleRect.onOver {
selectedButton.simulateHover()
dropButton.simulateHover()
}
invisibleRect.onOut {
selectedButton.simulateOut()
dropButton.simulateOut()
}
invisibleRect.onClick {
showItems = !showItems
updatedSize()
}
}
override fun updatedSize() {
super.updatedSize()
itemsView.visible = showItems
itemsView.size(width, 196).position(0, height)
selectedButton.simulatePressing(showItems)
dropButton.simulatePressing(showItems)
dropButton.label = if (showItems) "-" else "+"
invisibleRect.size(width, height)
selectedButton.position(0, 0).size(width - buttonSize, height)
selectedButton.label = selectedItem?.toString() ?: ""
//println("selectedIndex: $selectedIndex, selectedItem: $selectedItem")
dropButton.position(width - buttonSize, 0).size(buttonSize, height)
}
protected fun updatedSelection() {
updatedSize()
for (n in items.indices) {
val button = itemsView.container.children[n] as? UIButton? ?: continue
button.forcePressed = selectedIndex == n
}
onUpdatedSelection(this)
}
protected fun updatedItems() {
itemsView.container.removeChildren()
for ((index, item) in items.withIndex()) {
val button = itemsView.container.uiButton(width - 32, itemHeight, label = item.toString(), skin = skin) {
position(0, index * itemHeight)
onClick {
showItems = false
selectedIndex = index
updatedSize()
}
}
}
itemsView.contentHeight = ((items.size) * itemHeight).toDouble()
updatedSelection()
}
}

View File

@@ -1,18 +0,0 @@
package com.soywiz.korge.newui
import kotlin.reflect.*
inline fun <T> uiObservable(value: T, noinline observe: () -> Unit) = UIObservable(value, observe)
class UIObservable<T>(val initial: T, val observe: () -> Unit) {
var currentValue = initial
operator fun getValue(obj: Any, prop: KProperty<*>): T {
return currentValue
}
operator fun setValue(obj: Any, prop: KProperty<*>, value: T) {
currentValue = value
observe()
}
}

View File

@@ -1,39 +0,0 @@
package com.soywiz.korge.newui
import com.soywiz.korge.view.*
inline fun Container.uiProgressBar(
width: Number = 256.0,
height: Number = 24.0,
current: Number = 0.0,
maximum: Number = 1.0,
skin: UISkin = defaultUISkin,
block: UIProgressBar.() -> Unit = {}
): UIProgressBar = UIProgressBar(width.toDouble(), height.toDouble(), current.toDouble(), maximum.toDouble(), skin).also { addChild(it) }.also(block)
open class UIProgressBar(
width: Double = 256.0,
height: Double = 24.0,
current: Double = 0.0,
maximum: Double = 1.0,
skin: UISkin = DefaultUISkin
) : UIView(width, height) {
var current: Double by uiObservable(current) { updatedSize() }
var maximum: Double by uiObservable(maximum) { updatedSize() }
override var ratio: Double
set(value) = run { current = value * maximum }
get() = current / maximum
private val bg = solidRect(width, height, skin.backColor)
private val progress = uiButton(width, height, "", skin = skin).also { mouseEnabled = false }
init {
updatedSize()
}
override fun updatedSize() {
bg.size(width, height)
progress.forcePressed = true
progress.size(width * ratio, height)
}
}

View File

@@ -1,124 +0,0 @@
package com.soywiz.korge.newui
import com.soywiz.kmem.*
import com.soywiz.korge.input.*
import com.soywiz.korge.view.*
import com.soywiz.korio.async.*
import com.soywiz.korma.geom.*
import kotlin.math.*
import kotlin.properties.*
inline fun Container.uiScrollBar(
width: Number,
height: Number,
current: Number = 0.0,
pageSize: Number = 1.0,
totalSize: Number = 10.0,
buttonSize: Number = 32.0,
direction: UIScrollBar.Direction = if (width.toDouble() > height.toDouble()) UIScrollBar.Direction.Horizontal else UIScrollBar.Direction.Vertical,
stepSize: Double = pageSize.toDouble() / 10.0,
skin: UISkin = defaultUISkin,
block: UIScrollBar.() -> Unit = {}
): UIScrollBar = UIScrollBar(width.toDouble(), height.toDouble(), current.toDouble(), pageSize.toDouble(), totalSize.toDouble(), buttonSize.toDouble(), direction, stepSize, skin).also { addChild(it) }.apply(block)
open class UIScrollBar(
width: Double,
height: Double,
current: Double,
pageSize: Double,
totalSize: Double,
buttonSize: Double = 32.0,
direction: Direction = if (width > height) Direction.Horizontal else Direction.Vertical,
var stepSize: Double = pageSize / 10.0,
skin: UISkin = DefaultUISkin
) : UIView() {
val onChange = Signal<UIScrollBar>()
enum class Direction { Vertical, Horizontal }
var current by uiObservable(current) { updatedPos() }
var pageSize by uiObservable(pageSize) { updatedPos() }
var totalSize by uiObservable(totalSize) { updatedPos() }
var direction by uiObservable(direction) { reshape() }
val isHorizontal get() = direction == Direction.Horizontal
val isVertical get() = direction == Direction.Vertical
override var ratio: Double
set(value) = run { current = value.clamp01() * (totalSize - pageSize) }
get() = (current / (totalSize - pageSize)).clamp(0.0, 1.0)
override var width: Double by uiObservable(width) { reshape() }
override var height: Double by uiObservable(height) { reshape() }
var buttonSize by uiObservable(buttonSize) { reshape() }
val buttonWidth get() = if (isHorizontal) buttonSize else width
val buttonHeight get() = if (isHorizontal) height else buttonSize
val clientWidth get() = if (isHorizontal) width - buttonWidth * 2 else width
val clientHeight get() = if (isHorizontal) height else height - buttonHeight * 2
protected val background = solidRect(100, 100, skin.backColor)
protected val lessButton = uiButton(16, 16, "-", skin = skin)
protected val moreButton = uiButton(16, 16, "+", skin = skin)
protected val caretButton = uiButton(16, 16, "", skin = skin)
protected val views get() = stage?.views
init {
reshape()
var slx: Double = 0.0
var sly: Double = 0.0
var iratio: Double = 0.0
var sratio: Double = 0.0
val tempP = Point()
lessButton.onDown {
deltaCurrent(-stepSize)
reshape()
}
moreButton.onDown {
deltaCurrent(+stepSize)
reshape()
}
background.onClick {
val pos = if (isHorizontal) caretButton.localMouseX(views!!) else caretButton.localMouseY(views!!)
deltaCurrent(this.pageSize * pos.sign)
}
caretButton.onMouseDrag {
val lmouse = background.localMouseXY(views, tempP)
val lx = lmouse.x
val ly = lmouse.y
val cratio = if (isHorizontal) lmouse.x / background.width else lmouse.y / background.height
if (it.start) {
slx = lx
sly = ly
iratio = ratio
sratio = cratio
}
val dratio = cratio - sratio
ratio = iratio + dratio
reshape()
}
}
private fun deltaCurrent(value: Double) {
//println("deltaCurrent: $value")
current = (current + value).clamp(0.0, totalSize - pageSize)
}
private fun reshape() {
if (isHorizontal) {
background.position(buttonWidth, 0).size(clientWidth, clientHeight)
lessButton.position(0, 0).size(buttonWidth, buttonHeight)
moreButton.position(width - buttonWidth, 0).size(buttonWidth, buttonHeight)
val caretWidth = (clientWidth * (pageSize / totalSize)).clamp(4.0, clientWidth)
caretButton.position(buttonWidth + (clientWidth - caretWidth) * ratio, 0).size(caretWidth, buttonHeight)
} else {
background.position(0, buttonHeight).size(clientWidth, clientHeight)
lessButton.position(0, 0).size(buttonWidth, buttonHeight)
moreButton.position(0, height - buttonHeight).size(buttonWidth, buttonHeight)
val caretHeight = (clientHeight * (pageSize / totalSize)).clamp(4.0, clientHeight)
caretButton.position(0, buttonHeight + (clientHeight - caretHeight) * ratio).size(buttonWidth, caretHeight)
}
}
private fun updatedPos() {
reshape()
onChange(this)
}
}

View File

@@ -1,75 +0,0 @@
package com.soywiz.korge.newui
import com.soywiz.korge.view.*
inline fun Container.uiScrollableArea(
width: Number = 256.0,
height: Number = 256.0,
contentWidth: Number = 512.0,
contentHeight: Number = 512.0,
buttonSize: Number = 32.0,
verticalScroll: Boolean = true,
horizontalScroll: Boolean = true,
skin: UISkin = defaultUISkin,
config: UIScrollableArea.() -> Unit = {},
block: Container.() -> Unit = {}
): UIScrollableArea = UIScrollableArea(
width.toDouble(), height.toDouble(), contentWidth.toDouble(), contentHeight.toDouble(), buttonSize.toDouble(), verticalScroll, horizontalScroll, skin
).also { addChild(it) }.also(config).also { block(it.container) }
// @TODO: Optimize this!
// @TODO: Add an actualContainer = this inside Container
open class UIScrollableArea(
width: Double = 256.0,
height: Double = 256.0,
contentWidth: Double = 512.0,
contentHeight: Double = 512.0,
buttonSize: Double = 32.0,
verticalScroll: Boolean = true,
horizontalScroll: Boolean = true,
skin: UISkin = DefaultUISkin
) : UIView(width, height) {
var buttonSize by uiObservable(buttonSize) { updatedSize() }
var contentWidth by uiObservable(contentWidth) { updatedSize() }
var contentHeight by uiObservable(contentHeight) { updatedSize() }
var verticalScroll by uiObservable(verticalScroll) { updatedSize() }
var horizontalScroll by uiObservable(horizontalScroll) { updatedSize() }
val clientWidth get() = if (verticalScroll) width - buttonSize else width
val clientHeight get() = if (horizontalScroll) height - buttonSize else height
val clipContainer = clipContainer(clientWidth, clientHeight)
val container = clipContainer.fixedSizeContainer(contentWidth, contentHeight)
val horScroll = uiScrollBar(width, buttonSize, skin = skin).also { it.onChange { moved() } }
val verScroll = uiScrollBar(buttonSize, height, skin = skin).also { it.onChange { moved() } }
init {
updatedSize()
}
override fun updatedSize() {
super.updatedSize()
horScroll.totalSize = contentWidth
horScroll.pageSize = clientWidth
horScroll.stepSize = clientWidth / 4
verScroll.totalSize = contentHeight
verScroll.pageSize = clientHeight
verScroll.stepSize = clientHeight / 4
clipContainer.size(clientWidth, clientHeight)
container.size(contentWidth, contentHeight)
horScroll.size(clientWidth, buttonSize).position(0, height - buttonSize).also { it.visible = horizontalScroll }
verScroll.size(buttonSize, clientHeight).position(width - buttonSize, 0).also { it.visible = verticalScroll }
}
protected fun moved() {
//println("" + verScroll.current + " :: " + verScroll.totalSize + " :: " + verScroll.pageSize + " :: " + verScroll.stepSize)
container.x = -horScroll.current
container.y = -verScroll.current
}
}

View File

@@ -1,26 +0,0 @@
package com.soywiz.korge.newui
import com.soywiz.kds.*
import com.soywiz.korge.html.*
import com.soywiz.korge.view.*
import com.soywiz.korim.bitmap.*
import com.soywiz.korim.color.*
@PublishedApi
internal var View.internalDefaultUISkin: UISkin? by extraProperty("defaultUiSkin") { null }
var View.defaultUISkin: UISkin
set(value) = run { internalDefaultUISkin = value }
get() = internalDefaultUISkin ?: parent?.defaultUISkin ?: DefaultUISkin
fun Container.uiSkin(skin: UISkin, block: Container.() -> Unit) {
defaultUISkin = skin
block()
}
data class UISkin(
val normal: BmpSlice,
val hover: BmpSlice,
val down: BmpSlice,
val backColor: RGBA = Colors.DARKGREY,
val font: Html.FontFace = Html.FontFace.Named("Arial")
)

View File

@@ -1,60 +0,0 @@
package com.soywiz.korge.newui
import com.soywiz.kds.*
import com.soywiz.korge.component.*
import com.soywiz.korge.input.*
import com.soywiz.korge.render.*
import com.soywiz.korge.view.*
import kotlin.properties.*
open class UIView(
width: Double = 90.0,
height: Double = 32.0
) : Container() {
override var width: Double by uiObservable(width) { updatedSize() }
override var height: Double by uiObservable(height) { updatedSize() }
open var uiEnabled by uiObservable(true) { updateEnabled() }
open var uiDisabled: Boolean
set(value) = run { uiEnabled = !value }
get() = !uiEnabled
fun enable(set: Boolean = true) = run { uiEnabled = set }
fun disable() = run { uiEnabled = false }
protected open fun updatedSize() {
}
protected open fun updateEnabled() {
mouseEnabled = uiEnabled
// @TODO: Shouldn't change alpha
alpha = if (uiEnabled) 1.0 else 0.7
}
override fun renderInternal(ctx: RenderContext) {
registerUISupportOnce()
super.renderInternal(ctx)
}
private var registered = false
private fun registerUISupportOnce() {
if (registered) return
val stage = stage ?: return
registered = true
if (stage.getExtra("uiSupport") == true) return
stage.setExtra("uiSupport", true)
stage.keys {
onKeyDown {
}
}
stage?.getOrCreateComponent { stage ->
object : UpdateComponentWithViews {
override val view: View = stage
override fun update(views: Views, ms: Double) {
}
}
}
}
}