From 8f4ccbe00b65cbb95dc7d78a6af9b7c3161d49dc Mon Sep 17 00:00:00 2001 From: Baitinq Date: Fri, 20 Jan 2023 02:12:41 +0100 Subject: [PATCH 1/2] AbstractSetting: Add "formatter" parameter This patch adds a new "formatter: (T) -> String" parameter to the AbstractSetting abstract class. This allows for formatter functions to be passed to settings for them to display their value in a more user friendly way :) A possible usage of this would be to replace the unit parameter, as it simply concatenates the unit string to the setting value, which is a bit misleading IMO. --- .../client/setting/configs/PluginConfig.kt | 32 ++++++++--------- .../setting/settings/AbstractSetting.kt | 3 +- .../setting/settings/ImmutableSetting.kt | 1 + .../client/setting/settings/MutableSetting.kt | 1 + .../setting/settings/SettingRegister.kt | 35 ++++++++++++------- .../impl/collection/CollectionSetting.kt | 6 ++-- .../settings/impl/collection/MapSetting.kt | 5 +-- .../settings/impl/number/DoubleSetting.kt | 5 +-- .../settings/impl/number/FloatSetting.kt | 5 +-- .../settings/impl/number/IntegerSetting.kt | 5 +-- .../settings/impl/number/NumberSetting.kt | 3 +- .../settings/impl/other/BindSetting.kt | 5 +-- .../settings/impl/other/ColorSetting.kt | 5 +-- .../settings/impl/primitive/BooleanSetting.kt | 5 +-- .../settings/impl/primitive/EnumSetting.kt | 5 +-- .../settings/impl/primitive/StringSetting.kt | 5 +-- 16 files changed, 75 insertions(+), 51 deletions(-) diff --git a/src/main/kotlin/com/lambda/client/setting/configs/PluginConfig.kt b/src/main/kotlin/com/lambda/client/setting/configs/PluginConfig.kt index ae597b137..1ef312fed 100644 --- a/src/main/kotlin/com/lambda/client/setting/configs/PluginConfig.kt +++ b/src/main/kotlin/com/lambda/client/setting/configs/PluginConfig.kt @@ -51,35 +51,35 @@ class PluginConfig(pluginName: String) : NameableConfig( } ?: emptyList() } - override fun > IPluginClass.setting(name: String, value: E, visibility: () -> Boolean, consumer: (prev: E, input: E) -> E, description: String): EnumSetting { - return setting(EnumSetting(name, value, visibility, consumer, description)) + override fun > IPluginClass.setting(name: String, value: E, visibility: () -> Boolean, consumer: (prev: E, input: E) -> E, description: String, unit: String, formatter: (E) -> String): EnumSetting { + return setting(EnumSetting(name, value, visibility, consumer, description, unit, formatter)) } - override fun IPluginClass.setting(name: String, value: Boolean, visibility: () -> Boolean, consumer: (prev: Boolean, input: Boolean) -> Boolean, description: String): BooleanSetting { - return setting(BooleanSetting(name, value, visibility, consumer, description)) + override fun IPluginClass.setting(name: String, value: Boolean, visibility: () -> Boolean, consumer: (prev: Boolean, input: Boolean) -> Boolean, description: String, formatter: (Boolean) -> String): BooleanSetting { + return setting(BooleanSetting(name, value, visibility, consumer, description, formatter)) } - override fun IPluginClass.setting(name: String, value: ColorHolder, hasAlpha: Boolean, visibility: () -> Boolean, description: String): ColorSetting { - return setting(ColorSetting(name, value, hasAlpha, visibility, description)) + override fun IPluginClass.setting(name: String, value: ColorHolder, hasAlpha: Boolean, visibility: () -> Boolean, description: String, formatter: (ColorHolder) -> String): ColorSetting { + return setting(ColorSetting(name, value, hasAlpha, visibility, description, formatter)) } - override fun IPluginClass.setting(name: String, value: String, visibility: () -> Boolean, consumer: (prev: String, input: String) -> String, description: String): StringSetting { - return setting(StringSetting(name, value, visibility, consumer, description)) + override fun IPluginClass.setting(name: String, value: String, visibility: () -> Boolean, consumer: (prev: String, input: String) -> String, description: String, formatter: (String) -> String): StringSetting { + return setting(StringSetting(name, value, visibility, consumer, description, formatter)) } - override fun IPluginClass.setting(name: String, value: Double, range: ClosedFloatingPointRange, step: Double, visibility: () -> Boolean, consumer: (prev: Double, input: Double) -> Double, description: String, unit: String, fineStep: Double): DoubleSetting { - return setting(DoubleSetting(name, value, range, step, visibility, consumer, description, unit, fineStep)) + override fun IPluginClass.setting(name: String, value: Double, range: ClosedFloatingPointRange, step: Double, visibility: () -> Boolean, consumer: (prev: Double, input: Double) -> Double, description: String, unit: String, fineStep: Double, formatter: (Double) -> String): DoubleSetting { + return setting(DoubleSetting(name, value, range, step, visibility, consumer, description, unit, fineStep, formatter)) } - override fun IPluginClass.setting(name: String, value: Float, range: ClosedFloatingPointRange, step: Float, visibility: () -> Boolean, consumer: (prev: Float, input: Float) -> Float, description: String, unit: String, fineStep: Float): FloatSetting { - return setting(FloatSetting(name, value, range, step, visibility, consumer, description, unit, fineStep)) + override fun IPluginClass.setting(name: String, value: Float, range: ClosedFloatingPointRange, step: Float, visibility: () -> Boolean, consumer: (prev: Float, input: Float) -> Float, description: String, unit: String, fineStep: Float, formatter: (Float) -> String): FloatSetting { + return setting(FloatSetting(name, value, range, step, visibility, consumer, description, unit, fineStep, formatter)) } - override fun IPluginClass.setting(name: String, value: Int, range: IntRange, step: Int, visibility: () -> Boolean, consumer: (prev: Int, input: Int) -> Int, description: String, unit: String, fineStep: Int): IntegerSetting { - return setting(IntegerSetting(name, value, range, step, visibility, consumer, description, unit, fineStep)) + override fun IPluginClass.setting(name: String, value: Int, range: IntRange, step: Int, visibility: () -> Boolean, consumer: (prev: Int, input: Int) -> Int, description: String, unit: String, fineStep: Int, formatter: (Int) -> String): IntegerSetting { + return setting(IntegerSetting(name, value, range, step, visibility, consumer, description, unit, fineStep, formatter)) } - override fun IPluginClass.setting(name: String, value: Bind, visibility: () -> Boolean, description: String): BindSetting { - return setting(BindSetting(name, value, visibility, description)) + override fun IPluginClass.setting(name: String, value: Bind, visibility: () -> Boolean, description: String, formatter: (Bind) -> String): BindSetting { + return setting(BindSetting(name, value, visibility, description, formatter)) } } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/client/setting/settings/AbstractSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/AbstractSetting.kt index 2867e07ab..79bacfd32 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/AbstractSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/AbstractSetting.kt @@ -15,6 +15,7 @@ abstract class AbstractSetting : Nameable { abstract val visibility: () -> Boolean abstract val description: String abstract val unit: String + abstract val formatter: (T) -> String val listeners = ArrayList<() -> Unit>() val valueListeners = ArrayList<(prev: T, input: T) -> Unit>() @@ -34,7 +35,7 @@ abstract class AbstractSetting : Nameable { abstract fun write(): JsonElement abstract fun read(jsonElement: JsonElement?) - override fun toString() = "$value$unit" + override fun toString() = "${formatter(value)}$unit" override fun equals(other: Any?) = this === other || (other is AbstractSetting<*> diff --git a/src/main/kotlin/com/lambda/client/setting/settings/ImmutableSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/ImmutableSetting.kt index 9ad33535b..16419bef7 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/ImmutableSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/ImmutableSetting.kt @@ -15,6 +15,7 @@ abstract class ImmutableSetting( override val visibility: () -> Boolean, val consumer: (prev: T, input: T) -> T, override val description: String, + override val formatter: (T) -> String, override val unit: String ) : AbstractSetting() { override val value: T = valueIn diff --git a/src/main/kotlin/com/lambda/client/setting/settings/MutableSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/MutableSetting.kt index 05ee5b3d8..6fc4d46c0 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/MutableSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/MutableSetting.kt @@ -18,6 +18,7 @@ open class MutableSetting( override val visibility: () -> Boolean, consumer: (prev: T, input: T) -> T, override val description: String, + override val formatter: (T) -> String, override val unit: String ) : AbstractSetting() { diff --git a/src/main/kotlin/com/lambda/client/setting/settings/SettingRegister.kt b/src/main/kotlin/com/lambda/client/setting/settings/SettingRegister.kt index fa781204c..71a45d635 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/SettingRegister.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/SettingRegister.kt @@ -30,7 +30,8 @@ interface SettingRegister { description: String = "", unit: String = "", fineStep: Int = step, - ) = setting(IntegerSetting(name, value, range, step, visibility, consumer, description, unit, fineStep)) + formatter: (Int) -> String = { i -> "$i"}, + ) = setting(IntegerSetting(name, value, range, step, visibility, consumer, description, unit, fineStep, formatter)) /** Double Setting */ fun T.setting( @@ -43,7 +44,8 @@ interface SettingRegister { description: String = "", unit: String = "", fineStep: Double = step, - ) = setting(DoubleSetting(name, value, range, step, visibility, consumer, description, unit, fineStep)) + formatter: (Double) -> String = { d -> "$d"}, + ) = setting(DoubleSetting(name, value, range, step, visibility, consumer, description, unit, fineStep, formatter)) /** Float Setting */ fun T.setting( @@ -56,15 +58,17 @@ interface SettingRegister { description: String = "", unit: String = "", fineStep: Float = step, - ) = setting(FloatSetting(name, value, range, step, visibility, consumer, description, unit, fineStep)) + formatter: (Float) -> String = { f -> "$f"}, + ) = setting(FloatSetting(name, value, range, step, visibility, consumer, description, unit, fineStep, formatter)) /** Bind Setting */ fun T.setting( name: String, value: Bind, visibility: () -> Boolean = { true }, - description: String = "" - ) = setting(BindSetting(name, value, visibility, description)) + description: String = "", + formatter: (Bind) -> String = { b -> "$b"}, + ) = setting(BindSetting(name, value, visibility, description, formatter)) /** Color Setting */ fun T.setting( @@ -72,8 +76,9 @@ interface SettingRegister { value: ColorHolder, hasAlpha: Boolean = true, visibility: () -> Boolean = { true }, - description: String = "" - ) = setting(ColorSetting(name, value, hasAlpha, visibility, description)) + description: String = "", + formatter: (ColorHolder) -> String = { c -> "$c"}, + ) = setting(ColorSetting(name, value, hasAlpha, visibility, description, formatter)) /** Boolean Setting */ fun T.setting( @@ -81,8 +86,9 @@ interface SettingRegister { value: Boolean, visibility: () -> Boolean = { true }, consumer: (prev: Boolean, input: Boolean) -> Boolean = { _, input -> input }, - description: String = "" - ) = setting(BooleanSetting(name, value, visibility, consumer, description)) + description: String = "", + formatter: (Boolean) -> String = { b -> "$b"}, + ) = setting(BooleanSetting(name, value, visibility, consumer, description, formatter)) /** Enum Setting */ fun > T.setting( @@ -90,8 +96,10 @@ interface SettingRegister { value: E, visibility: () -> Boolean = { true }, consumer: (prev: E, input: E) -> E = { _, input -> input }, - description: String = "" - ) = setting(EnumSetting(name, value, visibility, consumer, description)) + description: String = "", + unit: String = "", + formatter: (E) -> String = { e -> "$e"}, + ) = setting(EnumSetting(name, value, visibility, consumer, description, unit, formatter)) /** String Setting */ fun T.setting( @@ -99,8 +107,9 @@ interface SettingRegister { value: String, visibility: () -> Boolean = { true }, consumer: (prev: String, input: String) -> String = { _, input -> input }, - description: String = "" - ) = setting(StringSetting(name, value, visibility, consumer, description)) + description: String = "", + formatter: (String) -> String = { s -> s }, + ) = setting(StringSetting(name, value, visibility, consumer, description, formatter)) /* End of setting registering */ fun AbstractSetting.atValue(page: T): () -> Boolean = { diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/collection/CollectionSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/collection/CollectionSetting.kt index d621471d4..72114f20a 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/collection/CollectionSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/collection/CollectionSetting.kt @@ -3,14 +3,16 @@ package com.lambda.client.setting.settings.impl.collection import com.google.gson.JsonElement import com.google.gson.reflect.TypeToken import com.lambda.client.setting.settings.ImmutableSetting +import com.lambda.client.util.color.ColorHolder class CollectionSetting>( name: String, override val value: T, visibility: () -> Boolean = { true }, description: String = "", - unit: String = "" -) : ImmutableSetting(name, value, visibility, { _, input -> input }, description, unit), MutableCollection by value { + unit: String = "", + formatter: (T) -> String = { c -> "$c"}, + ) : ImmutableSetting(name, value, visibility, { _, input -> input }, description, formatter, unit), MutableCollection by value { override val defaultValue: T = valueClass.newInstance() private val lockObject = Any() diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/collection/MapSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/collection/MapSetting.kt index e57f179b4..2874e969b 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/collection/MapSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/collection/MapSetting.kt @@ -9,8 +9,9 @@ class MapSetting>( override val value: T, visibility: () -> Boolean = { true }, description: String = "", - unit: String = "" -) : ImmutableSetting(name, value, visibility, { _, input -> input }, description, unit) { + unit: String = "", + formatter: (T) -> String = {m -> "$m"}, + ) : ImmutableSetting(name, value, visibility, { _, input -> input }, description, formatter, unit) { override val defaultValue: T = valueClass.newInstance() private val type = object : TypeToken>() {}.type diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/number/DoubleSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/number/DoubleSetting.kt index f4683bc78..359c06999 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/number/DoubleSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/number/DoubleSetting.kt @@ -11,8 +11,9 @@ class DoubleSetting( consumer: (prev: Double, input: Double) -> Double = { _, input -> input }, description: String = "", unit: String = "", - fineStep: Double = step -) : NumberSetting(name, value, range, step, visibility, consumer, description, unit, fineStep) { + fineStep: Double = step, + formatter: (Double) -> String = { d -> "$d"}, + ) : NumberSetting(name, value, range, step, visibility, consumer, description, formatter, unit, fineStep) { init { consumers.add(0) { _, it -> diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/number/FloatSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/number/FloatSetting.kt index eca89ff2f..25339db03 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/number/FloatSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/number/FloatSetting.kt @@ -11,8 +11,9 @@ class FloatSetting( consumer: (prev: Float, input: Float) -> Float = { _, input -> input }, description: String = "", unit: String = "", - fineStep: Float = step -) : NumberSetting(name, value, range, step, visibility, consumer, description, unit, fineStep) { + fineStep: Float = step, + formatter: (Float) -> String = { f -> "$f"}, + ) : NumberSetting(name, value, range, step, visibility, consumer, description, formatter, unit, fineStep) { init { consumers.add(0) { _, it -> diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/number/IntegerSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/number/IntegerSetting.kt index c800991b6..17e4df69d 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/number/IntegerSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/number/IntegerSetting.kt @@ -11,8 +11,9 @@ class IntegerSetting( consumer: (prev: Int, input: Int) -> Int = { _, input -> input }, description: String = "", unit: String = "", - fineStep: Int = step -) : NumberSetting(name, value, range, step, visibility, consumer, description, unit, fineStep) { + fineStep: Int = step, + formatter: (Int) -> String = { i -> "$i"}, + ) : NumberSetting(name, value, range, step, visibility, consumer, description, formatter, unit, fineStep) { init { consumers.add(0) { _, it -> diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/number/NumberSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/number/NumberSetting.kt index 21658ca53..3f39b8130 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/number/NumberSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/number/NumberSetting.kt @@ -11,9 +11,10 @@ abstract class NumberSetting( visibility: () -> Boolean, consumer: (prev: T, input: T) -> T, description: String = "", + formatter: (T) -> String, unit: String = "", val fineStep: T -) : MutableSetting(name, value, visibility, consumer, description, unit) +) : MutableSetting(name, value, visibility, consumer, description, formatter, unit) where T : Number, T : Comparable { override fun write() = JsonPrimitive(value) diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/other/BindSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/other/BindSetting.kt index 23e224f27..861c61b07 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/other/BindSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/other/BindSetting.kt @@ -11,8 +11,9 @@ class BindSetting( name: String, value: Bind, visibility: () -> Boolean = { true }, - description: String = "" -) : ImmutableSetting(name, value, visibility, { _, input -> input }, description, unit = "") { + description: String = "", + formatter: (Bind) -> String = { b -> "$b"}, + ) : ImmutableSetting(name, value, visibility, { _, input -> input }, description, formatter, unit = "") { override val defaultValue: Bind = Bind(TreeSet(value.modifierKeys), value.key, null) diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/other/ColorSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/other/ColorSetting.kt index 3feb506e4..7ef5b07af 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/other/ColorSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/other/ColorSetting.kt @@ -8,5 +8,6 @@ class ColorSetting( value: ColorHolder, val hasAlpha: Boolean = true, visibility: () -> Boolean = { true }, - description: String = "" -) : MutableSetting(name, value, visibility, { _, input -> if (!hasAlpha) input.apply { a = 255 } else input }, description, unit = "") \ No newline at end of file + description: String = "", + formatter: (ColorHolder) -> String = { c -> "$c"}, + ) : MutableSetting(name, value, visibility, { _, input -> if (!hasAlpha) input.apply { a = 255 } else input }, description, formatter, unit = "") \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/BooleanSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/BooleanSetting.kt index 4f8d9cb54..6722ceebb 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/BooleanSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/BooleanSetting.kt @@ -9,8 +9,9 @@ open class BooleanSetting( value: Boolean, visibility: () -> Boolean = { true }, consumer: (prev: Boolean, input: Boolean) -> Boolean = { _, input -> input }, - description: String = "" -) : MutableSetting(name, value, visibility, consumer, description, unit = "") { + description: String = "", + formatter: (Boolean) -> String = { b -> "$b"}, + ) : MutableSetting(name, value, visibility, consumer, description, formatter, unit = "") { override fun write(): JsonElement = JsonPrimitive(value) diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/EnumSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/EnumSetting.kt index b3a4127ad..639e04c32 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/EnumSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/EnumSetting.kt @@ -11,8 +11,9 @@ class EnumSetting>( visibility: () -> Boolean = { true }, consumer: (prev: T, input: T) -> T = { _, input -> input }, description: String = "", - unit: String = "" -) : MutableSetting(name, value, visibility, consumer, description, unit) { + unit: String = "", + formatter: (T) -> String = { e -> "$e"}, + ) : MutableSetting(name, value, visibility, consumer, description, formatter, unit) { private val enumClass: Class = value.declaringJavaClass val enumValues: Array = enumClass.enumConstants diff --git a/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/StringSetting.kt b/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/StringSetting.kt index 4eb37da4b..80c320a80 100644 --- a/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/StringSetting.kt +++ b/src/main/kotlin/com/lambda/client/setting/settings/impl/primitive/StringSetting.kt @@ -9,8 +9,9 @@ class StringSetting( value: String, visibility: () -> Boolean = { true }, consumer: (prev: String, input: String) -> String = { _, input -> input }, - description: String = "" -) : MutableSetting(name, value, visibility, consumer, description, unit = "") { + description: String = "", + formatter: (String) -> String = { s -> s }, + ) : MutableSetting(name, value, visibility, consumer, description, formatter, unit = "") { override fun setValue(valueIn: String) { value = valueIn From 1229c0bcd88602e26a3d0842c07d168a9fd0bbf5 Mon Sep 17 00:00:00 2001 From: Baitinq Date: Fri, 20 Jan 2023 02:21:55 +0100 Subject: [PATCH 2/2] AntiDisconnect: Use formatter in the button presses setting We now show "$x presses" by using the newly added setting formatter --- .../com/lambda/client/module/modules/misc/AntiDisconnect.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/lambda/client/module/modules/misc/AntiDisconnect.kt b/src/main/kotlin/com/lambda/client/module/modules/misc/AntiDisconnect.kt index 4c3950b46..11a1e756d 100644 --- a/src/main/kotlin/com/lambda/client/module/modules/misc/AntiDisconnect.kt +++ b/src/main/kotlin/com/lambda/client/module/modules/misc/AntiDisconnect.kt @@ -8,5 +8,5 @@ object AntiDisconnect : Module( description = "Prevents you from accidently disconnecting", category = Category.MISC ) { - val presses by setting("Button Presses", 3, 1..20, 1) + val presses by setting("Button Presses", 3, 1..20, 1, formatter = {i -> "$i presses"}) }