mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-27 22:06:05 -04:00
Split off stuff from CameraStageBaseScreen that isn't the class itself (#3929)
This commit is contained in:
parent
d546b2b00e
commit
abaa678e2b
@ -11,87 +11,11 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas
|
||||
import com.badlogic.gdx.scenes.scene2d.*
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.*
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.Drawable
|
||||
import com.badlogic.gdx.utils.viewport.ExtendViewport
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.models.Tutorial
|
||||
import com.unciv.models.UncivSound
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.tutorials.TutorialController
|
||||
import java.util.HashMap
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.random.Random
|
||||
|
||||
/*
|
||||
* For now, combination keys cannot easily be expressed.
|
||||
* Pressing Ctrl-Letter will arrive one event for Input.Keys.CONTROL_LEFT and one for the ASCII control code point
|
||||
* so Ctrl-R can be handled using KeyCharAndCode('\u0012')
|
||||
* Pressing Alt-Something likewise will fire once for Alt and once for the unmodified keys with no indication Alt is held
|
||||
* (Exception: international keyboard AltGr-combos)
|
||||
* An update supporting easy declarations for any modifier combos would need to use Gdx.input.isKeyPressed()
|
||||
* Gdx seems to omit support for a modifier mask (e.g. Ctrl-Alt-Shift) so we would need to reinvent this
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a key for use in an InputListener keyTyped() handler
|
||||
*
|
||||
* Example: KeyCharAndCode('R'), KeyCharAndCode(Input.Keys.F1)
|
||||
*/
|
||||
data class KeyCharAndCode(val char: Char, val code: Int) {
|
||||
// express keys with a Char value
|
||||
constructor(char: Char): this(char.toLowerCase(), 0)
|
||||
// express keys that only have a keyCode like F1
|
||||
constructor(code: Int): this(Char.MIN_VALUE, code)
|
||||
// helper for use in InputListener keyTyped()
|
||||
constructor(event: InputEvent?, character: Char)
|
||||
: this (
|
||||
character.toLowerCase(),
|
||||
if (character == Char.MIN_VALUE && event!=null) event.keyCode else 0
|
||||
)
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
override fun toString(): String {
|
||||
// debug helper
|
||||
return when {
|
||||
char == Char.MIN_VALUE -> Input.Keys.toString(code)
|
||||
char < ' ' -> "Ctrl-" + Char(char.toInt()+64)
|
||||
else -> "\"$char\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KeyPressDispatcher: HashMap<KeyCharAndCode, (() -> Unit)>() {
|
||||
private var checkpoint: Set<KeyCharAndCode> = setOf()
|
||||
|
||||
// access by Char
|
||||
operator fun get(char: Char) = this[KeyCharAndCode(char)]
|
||||
operator fun set(char: Char, action: () -> Unit) {
|
||||
this[KeyCharAndCode(char)] = action
|
||||
}
|
||||
operator fun contains(char: Char) = this.contains(KeyCharAndCode(char))
|
||||
fun remove(char: Char) = this.remove(KeyCharAndCode(char))
|
||||
|
||||
// access by Int keyCodes
|
||||
operator fun get(code: Int) = this[KeyCharAndCode(code)]
|
||||
operator fun set(code: Int, action: () -> Unit) {
|
||||
this[KeyCharAndCode(code)] = action
|
||||
}
|
||||
operator fun contains(code: Int) = this.contains(KeyCharAndCode(code))
|
||||
fun remove(code: Int) = this.remove(KeyCharAndCode(code))
|
||||
|
||||
override fun clear() {
|
||||
checkpoint = setOf()
|
||||
super.clear()
|
||||
}
|
||||
fun setCheckpoint() {
|
||||
checkpoint = keys.toSet()
|
||||
}
|
||||
fun revertToCheckPoint() {
|
||||
keys.minus(checkpoint).forEach { remove(it) }
|
||||
}
|
||||
}
|
||||
|
||||
open class CameraStageBaseScreen : Screen {
|
||||
|
||||
@ -195,176 +119,3 @@ open class CameraStageBaseScreen : Screen {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun Button.disable(){
|
||||
touchable= Touchable.disabled
|
||||
color= Color.GRAY
|
||||
}
|
||||
fun Button.enable() {
|
||||
color = Color.WHITE
|
||||
touchable = Touchable.enabled
|
||||
}
|
||||
var Button.isEnabled: Boolean
|
||||
//Todo: Use in PromotionPickerScreen, TradeTable, WorldScreen.updateNextTurnButton
|
||||
get() = touchable == Touchable.enabled
|
||||
set(value) = if (value) enable() else disable()
|
||||
|
||||
fun colorFromRGB(r: Int, g: Int, b: Int) = Color(r/255f, g/255f, b/255f, 1f)
|
||||
fun colorFromRGB(rgb:List<Int>) = colorFromRGB(rgb[0],rgb[1],rgb[2])
|
||||
|
||||
fun Actor.centerX(parent:Actor){ x = parent.width/2 - width/2 }
|
||||
fun Actor.centerY(parent:Actor){ y = parent.height/2- height/2}
|
||||
fun Actor.center(parent:Actor){ centerX(parent); centerY(parent)}
|
||||
|
||||
fun Actor.centerX(parent:Stage){ x = parent.width/2 - width/2 }
|
||||
fun Actor.centerY(parent:Stage){ y = parent.height/2- height/2}
|
||||
fun Actor.center(parent:Stage){ centerX(parent); centerY(parent)}
|
||||
|
||||
|
||||
/** same as [onClick], but sends the [InputEvent] and coordinates along */
|
||||
fun Actor.onClickEvent(sound: UncivSound = UncivSound.Click, function: (event: InputEvent?, x: Float, y: Float) -> Unit) {
|
||||
this.addListener(object : ClickListener() {
|
||||
override fun clicked(event: InputEvent?, x: Float, y: Float) {
|
||||
thread(name="Sound") { Sounds.play(sound) }
|
||||
function(event, x, y)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// If there are other buttons that require special clicks then we'll have an onclick that will accept a string parameter, no worries
|
||||
fun Actor.onClick(sound: UncivSound = UncivSound.Click, function: () -> Unit) {
|
||||
onClickEvent(sound) { _, _, _ -> function() }
|
||||
}
|
||||
|
||||
fun Actor.onClick(function: () -> Unit): Actor {
|
||||
onClick(UncivSound.Click, function)
|
||||
return this
|
||||
}
|
||||
|
||||
fun Actor.onChange(function: () -> Unit): Actor {
|
||||
this.addListener(object : ChangeListener() {
|
||||
override fun changed(event: ChangeEvent?, actor: Actor?) {
|
||||
function()
|
||||
}
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
fun Actor.surroundWithCircle(size: Float, resizeActor: Boolean = true, color: Color = Color.WHITE): IconCircleGroup {
|
||||
return IconCircleGroup(size,this,resizeActor, color)
|
||||
}
|
||||
|
||||
fun Actor.addBorder(size:Float,color:Color,expandCell:Boolean=false):Table{
|
||||
val table = Table()
|
||||
table.pad(size)
|
||||
table.background = ImageGetter.getBackground(color)
|
||||
val cell = table.add(this)
|
||||
if (expandCell) cell.expand()
|
||||
cell.fill()
|
||||
table.pack()
|
||||
return table
|
||||
}
|
||||
|
||||
fun Table.addSeparator(): Cell<Image> {
|
||||
row()
|
||||
val image = ImageGetter.getWhiteDot()
|
||||
val cell = add(image).colspan(columns).height(2f).fill()
|
||||
row()
|
||||
return cell
|
||||
}
|
||||
|
||||
fun Table.addSeparatorVertical(): Cell<Image> {
|
||||
val image = ImageGetter.getWhiteDot()
|
||||
val cell = add(image).width(2f).fillY()
|
||||
return cell
|
||||
}
|
||||
|
||||
fun <T : Actor> Table.addCell(actor: T): Table {
|
||||
add(actor)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
|
||||
*/
|
||||
fun <T> ArrayList<T>.withItem(item:T): ArrayList<T> {
|
||||
val newArrayList = ArrayList(this)
|
||||
newArrayList.add(item)
|
||||
return newArrayList
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
|
||||
*/
|
||||
fun <T> HashSet<T>.withItem(item:T): HashSet<T> {
|
||||
val newHashSet = HashSet(this)
|
||||
newHashSet.add(item)
|
||||
return newHashSet
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
|
||||
*/
|
||||
fun <T> ArrayList<T>.withoutItem(item:T): ArrayList<T> {
|
||||
val newArrayList = ArrayList(this)
|
||||
newArrayList.remove(item)
|
||||
return newArrayList
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
|
||||
*/
|
||||
fun <T> HashSet<T>.withoutItem(item:T): HashSet<T> {
|
||||
val newHashSet = HashSet(this)
|
||||
newHashSet.remove(item)
|
||||
return newHashSet
|
||||
}
|
||||
|
||||
fun String.toTextButton() = TextButton(this.tr(), CameraStageBaseScreen.skin)
|
||||
|
||||
/** also translates */
|
||||
fun String.toLabel() = Label(this.tr(),CameraStageBaseScreen.skin)
|
||||
fun Int.toLabel() = this.toString().toLabel()
|
||||
|
||||
|
||||
|
||||
// We don't want to use setFontSize and setFontColor because they set the font,
|
||||
// which means we need to rebuild the font cache which means more memory allocation.
|
||||
fun String.toLabel(fontColor:Color= Color.WHITE, fontSize:Int=18): Label {
|
||||
var labelStyle = CameraStageBaseScreen.skin.get(Label.LabelStyle::class.java)
|
||||
if(fontColor!= Color.WHITE || fontSize!=18) { // if we want the default we don't need to create another style
|
||||
labelStyle = Label.LabelStyle(labelStyle) // clone this to another
|
||||
labelStyle.fontColor = fontColor
|
||||
if (fontSize != 18) labelStyle.font = Fonts.font
|
||||
}
|
||||
return Label(this.tr(), labelStyle).apply { setFontScale(fontSize/Fonts.ORIGINAL_FONT_SIZE) }
|
||||
}
|
||||
|
||||
|
||||
fun Label.setFontColor(color:Color): Label { style=Label.LabelStyle(style).apply { fontColor=color }; return this }
|
||||
|
||||
fun Label.setFontSize(size:Int): Label {
|
||||
style = Label.LabelStyle(style)
|
||||
style.font = Fonts.font
|
||||
style = style // because we need it to call the SetStyle function. Yuk, I know.
|
||||
return this.apply { setFontScale(size/Fonts.ORIGINAL_FONT_SIZE) } // for chaining
|
||||
}
|
||||
|
||||
|
||||
fun <T> List<T>.randomWeighted(weights: List<Float>, random: Random = Random): T {
|
||||
if (this.isEmpty()) throw NoSuchElementException("Empty list.")
|
||||
if (this.size != weights.size) throw UnsupportedOperationException("Weights size does not match this list size.")
|
||||
|
||||
val totalWeight = weights.sum()
|
||||
val randDouble = random.nextDouble()
|
||||
var sum = 0f
|
||||
|
||||
for (i in weights.indices) {
|
||||
sum += weights[i] / totalWeight
|
||||
if (randDouble <= sum)
|
||||
return this[i]
|
||||
}
|
||||
return this.last()
|
||||
}
|
||||
|
187
core/src/com/unciv/ui/utils/ExtensionFunctions.kt
Normal file
187
core/src/com/unciv/ui/utils/ExtensionFunctions.kt
Normal file
@ -0,0 +1,187 @@
|
||||
package com.unciv.ui.utils
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent
|
||||
import com.badlogic.gdx.scenes.scene2d.Stage
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.*
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
|
||||
import com.unciv.models.UncivSound
|
||||
import com.unciv.models.translations.tr
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
fun Button.disable(){
|
||||
touchable= Touchable.disabled
|
||||
color= Color.GRAY
|
||||
}
|
||||
fun Button.enable() {
|
||||
color = Color.WHITE
|
||||
touchable = Touchable.enabled
|
||||
}
|
||||
var Button.isEnabled: Boolean
|
||||
//Todo: Use in PromotionPickerScreen, TradeTable, WorldScreen.updateNextTurnButton
|
||||
get() = touchable == Touchable.enabled
|
||||
set(value) = if (value) enable() else disable()
|
||||
|
||||
fun colorFromRGB(r: Int, g: Int, b: Int) = Color(r/255f, g/255f, b/255f, 1f)
|
||||
fun colorFromRGB(rgb:List<Int>) = colorFromRGB(rgb[0],rgb[1],rgb[2])
|
||||
|
||||
fun Actor.centerX(parent: Actor){ x = parent.width/2 - width/2 }
|
||||
fun Actor.centerY(parent: Actor){ y = parent.height/2- height/2}
|
||||
fun Actor.center(parent: Actor){ centerX(parent); centerY(parent)}
|
||||
|
||||
fun Actor.centerX(parent: Stage){ x = parent.width/2 - width/2 }
|
||||
fun Actor.centerY(parent: Stage){ y = parent.height/2- height/2}
|
||||
fun Actor.center(parent: Stage){ centerX(parent); centerY(parent)}
|
||||
|
||||
|
||||
/** same as [onClick], but sends the [InputEvent] and coordinates along */
|
||||
fun Actor.onClickEvent(sound: UncivSound = UncivSound.Click, function: (event: InputEvent?, x: Float, y: Float) -> Unit) {
|
||||
this.addListener(object : ClickListener() {
|
||||
override fun clicked(event: InputEvent?, x: Float, y: Float) {
|
||||
thread(name="Sound") { Sounds.play(sound) }
|
||||
function(event, x, y)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// If there are other buttons that require special clicks then we'll have an onclick that will accept a string parameter, no worries
|
||||
fun Actor.onClick(sound: UncivSound = UncivSound.Click, function: () -> Unit) {
|
||||
onClickEvent(sound) { _, _, _ -> function() }
|
||||
}
|
||||
|
||||
fun Actor.onClick(function: () -> Unit): Actor {
|
||||
onClick(UncivSound.Click, function)
|
||||
return this
|
||||
}
|
||||
|
||||
fun Actor.onChange(function: () -> Unit): Actor {
|
||||
this.addListener(object : ChangeListener() {
|
||||
override fun changed(event: ChangeEvent?, actor: Actor?) {
|
||||
function()
|
||||
}
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
fun Actor.surroundWithCircle(size: Float, resizeActor: Boolean = true, color: Color = Color.WHITE): IconCircleGroup {
|
||||
return IconCircleGroup(size,this,resizeActor, color)
|
||||
}
|
||||
|
||||
fun Actor.addBorder(size:Float, color: Color, expandCell:Boolean=false): Table {
|
||||
val table = Table()
|
||||
table.pad(size)
|
||||
table.background = ImageGetter.getBackground(color)
|
||||
val cell = table.add(this)
|
||||
if (expandCell) cell.expand()
|
||||
cell.fill()
|
||||
table.pack()
|
||||
return table
|
||||
}
|
||||
|
||||
fun Table.addSeparator(): Cell<Image> {
|
||||
row()
|
||||
val image = ImageGetter.getWhiteDot()
|
||||
val cell = add(image).colspan(columns).height(2f).fill()
|
||||
row()
|
||||
return cell
|
||||
}
|
||||
|
||||
fun Table.addSeparatorVertical(): Cell<Image> {
|
||||
val image = ImageGetter.getWhiteDot()
|
||||
val cell = add(image).width(2f).fillY()
|
||||
return cell
|
||||
}
|
||||
|
||||
fun <T : Actor> Table.addCell(actor: T): Table {
|
||||
add(actor)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
|
||||
*/
|
||||
fun <T> ArrayList<T>.withItem(item:T): ArrayList<T> {
|
||||
val newArrayList = ArrayList(this)
|
||||
newArrayList.add(item)
|
||||
return newArrayList
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
|
||||
*/
|
||||
fun <T> HashSet<T>.withItem(item:T): HashSet<T> {
|
||||
val newHashSet = HashSet(this)
|
||||
newHashSet.add(item)
|
||||
return newHashSet
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
|
||||
*/
|
||||
fun <T> ArrayList<T>.withoutItem(item:T): ArrayList<T> {
|
||||
val newArrayList = ArrayList(this)
|
||||
newArrayList.remove(item)
|
||||
return newArrayList
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
|
||||
*/
|
||||
fun <T> HashSet<T>.withoutItem(item:T): HashSet<T> {
|
||||
val newHashSet = HashSet(this)
|
||||
newHashSet.remove(item)
|
||||
return newHashSet
|
||||
}
|
||||
|
||||
fun String.toTextButton() = TextButton(this.tr(), CameraStageBaseScreen.skin)
|
||||
|
||||
/** also translates */
|
||||
fun String.toLabel() = Label(this.tr(),CameraStageBaseScreen.skin)
|
||||
fun Int.toLabel() = this.toString().toLabel()
|
||||
|
||||
|
||||
|
||||
// We don't want to use setFontSize and setFontColor because they set the font,
|
||||
// which means we need to rebuild the font cache which means more memory allocation.
|
||||
fun String.toLabel(fontColor: Color = Color.WHITE, fontSize:Int=18): Label {
|
||||
var labelStyle = CameraStageBaseScreen.skin.get(Label.LabelStyle::class.java)
|
||||
if(fontColor!= Color.WHITE || fontSize!=18) { // if we want the default we don't need to create another style
|
||||
labelStyle = Label.LabelStyle(labelStyle) // clone this to another
|
||||
labelStyle.fontColor = fontColor
|
||||
if (fontSize != 18) labelStyle.font = Fonts.font
|
||||
}
|
||||
return Label(this.tr(), labelStyle).apply { setFontScale(fontSize/Fonts.ORIGINAL_FONT_SIZE) }
|
||||
}
|
||||
|
||||
|
||||
fun Label.setFontColor(color: Color): Label { style= Label.LabelStyle(style).apply { fontColor=color }; return this }
|
||||
|
||||
fun Label.setFontSize(size:Int): Label {
|
||||
style = Label.LabelStyle(style)
|
||||
style.font = Fonts.font
|
||||
style = style // because we need it to call the SetStyle function. Yuk, I know.
|
||||
return this.apply { setFontScale(size/ Fonts.ORIGINAL_FONT_SIZE) } // for chaining
|
||||
}
|
||||
|
||||
|
||||
fun <T> List<T>.randomWeighted(weights: List<Float>, random: Random = Random): T {
|
||||
if (this.isEmpty()) throw NoSuchElementException("Empty list.")
|
||||
if (this.size != weights.size) throw UnsupportedOperationException("Weights size does not match this list size.")
|
||||
|
||||
val totalWeight = weights.sum()
|
||||
val randDouble = random.nextDouble()
|
||||
var sum = 0f
|
||||
|
||||
for (i in weights.indices) {
|
||||
sum += weights[i] / totalWeight
|
||||
if (randDouble <= sum)
|
||||
return this[i]
|
||||
}
|
||||
return this.last()
|
||||
}
|
74
core/src/com/unciv/ui/utils/KeyPressDispatcher.kt
Normal file
74
core/src/com/unciv/ui/utils/KeyPressDispatcher.kt
Normal file
@ -0,0 +1,74 @@
|
||||
package com.unciv.ui.utils
|
||||
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent
|
||||
import java.util.HashMap
|
||||
|
||||
/*
|
||||
* For now, combination keys cannot easily be expressed.
|
||||
* Pressing Ctrl-Letter will arrive one event for Input.Keys.CONTROL_LEFT and one for the ASCII control code point
|
||||
* so Ctrl-R can be handled using KeyCharAndCode('\u0012')
|
||||
* Pressing Alt-Something likewise will fire once for Alt and once for the unmodified keys with no indication Alt is held
|
||||
* (Exception: international keyboard AltGr-combos)
|
||||
* An update supporting easy declarations for any modifier combos would need to use Gdx.input.isKeyPressed()
|
||||
* Gdx seems to omit support for a modifier mask (e.g. Ctrl-Alt-Shift) so we would need to reinvent this
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a key for use in an InputListener keyTyped() handler
|
||||
*
|
||||
* Example: KeyCharAndCode('R'), KeyCharAndCode(Input.Keys.F1)
|
||||
*/
|
||||
data class KeyCharAndCode(val char: Char, val code: Int) {
|
||||
// express keys with a Char value
|
||||
constructor(char: Char): this(char.toLowerCase(), 0)
|
||||
// express keys that only have a keyCode like F1
|
||||
constructor(code: Int): this(Char.MIN_VALUE, code)
|
||||
// helper for use in InputListener keyTyped()
|
||||
constructor(event: InputEvent?, character: Char)
|
||||
: this (
|
||||
character.toLowerCase(),
|
||||
if (character == Char.MIN_VALUE && event!=null) event.keyCode else 0
|
||||
)
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
override fun toString(): String {
|
||||
// debug helper
|
||||
return when {
|
||||
char == Char.MIN_VALUE -> Input.Keys.toString(code)
|
||||
char < ' ' -> "Ctrl-" + Char(char.toInt()+64)
|
||||
else -> "\"$char\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KeyPressDispatcher: HashMap<KeyCharAndCode, (() -> Unit)>() {
|
||||
private var checkpoint: Set<KeyCharAndCode> = setOf()
|
||||
|
||||
// access by Char
|
||||
operator fun get(char: Char) = this[KeyCharAndCode(char)]
|
||||
operator fun set(char: Char, action: () -> Unit) {
|
||||
this[KeyCharAndCode(char)] = action
|
||||
}
|
||||
operator fun contains(char: Char) = this.contains(KeyCharAndCode(char))
|
||||
fun remove(char: Char) = this.remove(KeyCharAndCode(char))
|
||||
|
||||
// access by Int keyCodes
|
||||
operator fun get(code: Int) = this[KeyCharAndCode(code)]
|
||||
operator fun set(code: Int, action: () -> Unit) {
|
||||
this[KeyCharAndCode(code)] = action
|
||||
}
|
||||
operator fun contains(code: Int) = this.contains(KeyCharAndCode(code))
|
||||
fun remove(code: Int) = this.remove(KeyCharAndCode(code))
|
||||
|
||||
override fun clear() {
|
||||
checkpoint = setOf()
|
||||
super.clear()
|
||||
}
|
||||
fun setCheckpoint() {
|
||||
checkpoint = keys.toSet()
|
||||
}
|
||||
fun revertToCheckPoint() {
|
||||
keys.minus(checkpoint).forEach { remove(it) }
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user