Add DoubleListParameter annotation to orx-parameters

This commit is contained in:
Edwin Jakobs
2020-03-26 11:31:26 +01:00
parent 2daad2df57
commit 3f76e9fd3d
2 changed files with 64 additions and 15 deletions

View File

@@ -17,6 +17,7 @@ import kotlin.reflect.full.memberProperties
5. Add a test in TestAnnotations.kt 5. Add a test in TestAnnotations.kt
*/ */
//<editor-fold desc="1. Add an annotation class" defaultstate="collapsed">
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
annotation class Description(val title: String, val description: String = "") annotation class Description(val title: String, val description: String = "")
@@ -33,6 +34,29 @@ annotation class Description(val title: String, val description: String = "")
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
annotation class DoubleParameter(val label: String, val low: Double, val high: Double, val precision: Int = 3, val order: Int = Integer.MAX_VALUE) annotation class DoubleParameter(val label: String, val low: Double, val high: Double, val precision: Int = 3, val order: Int = Integer.MAX_VALUE)
/**
* DoubleListParameter annotation for a double precision parameter
* @property label a short description of the parameter
* @property low the lowest value this parameter should be assigned
* @property high the highest value this parameter should be assigned
* @property minimumListLength the minimum amount of entries the annotated list should contain
* @property maximumListLength the maximum amount of entries the annotated list should contain
* @property precision a hint for precision in user interfaces
* @property order hint for where to place the parameter in user interfaces
*/
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
annotation class DoubleListParameter(
val label: String,
val low: Double = -1.0,
val high: Double = 1.0,
val minimumListLength: Int = 1,
val maximumListLength: Int = 16,
val precision: Int = 3,
val order: Int = Integer.MAX_VALUE
)
/** /**
* IntParameter annotation for an integer parameter * IntParameter annotation for an integer parameter
* @property label a short description of the parameter * @property label a short description of the parameter
@@ -100,6 +124,8 @@ annotation class XYParameter(
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
annotation class ActionParameter(val label: String, val order: Int = Integer.MAX_VALUE) annotation class ActionParameter(val label: String, val order: Int = Integer.MAX_VALUE)
//</editor-fold>
//<editor-fold desc="2. Add an entry to ParameterType" id="add-parameter-type" defaultstate="collapsed">
enum class ParameterType(val annotationClass: KClass<out Annotation>) { enum class ParameterType(val annotationClass: KClass<out Annotation>) {
Double(DoubleParameter::class), Double(DoubleParameter::class),
Int(IntParameter::class), Int(IntParameter::class),
@@ -107,7 +133,8 @@ enum class ParameterType(val annotationClass: KClass<out Annotation>) {
Action(ActionParameter::class), Action(ActionParameter::class),
Text(TextParameter::class), Text(TextParameter::class),
Color(ColorParameter::class), Color(ColorParameter::class),
XY(XYParameter::class) XY(XYParameter::class),
DoubleList(DoubleListParameter::class)
; ;
companion object { companion object {
@@ -117,7 +144,8 @@ enum class ParameterType(val annotationClass: KClass<out Annotation>) {
val parameterAnnotationClasses get() = values().map { it.annotationClass } val parameterAnnotationClasses get() = values().map { it.annotationClass }
} }
} }
//</editor-fold>
//<editor-fold desc="3. Add extra fields (if any) to Parameter" defaultstate="collapsed">
/** /**
* Parameter summary class. This is used by [listParameters] as a way to report parameters in * Parameter summary class. This is used by [listParameters] as a way to report parameters in
* a unified form. * a unified form.
@@ -138,25 +166,28 @@ class Parameter(
val label: String, val label: String,
val doubleRange: ClosedRange<Double>?, val doubleRange: ClosedRange<Double>?,
val vectorRange: Pair<Vector2, Vector2>?, val vectorRange: Pair<Vector2, Vector2>?,
val sizeRange: ClosedRange<Int>?,
val intRange: IntRange?, val intRange: IntRange?,
val precision: Int?, val precision: Int?,
val invertY: Boolean?, val invertY: Boolean?,
val showVector: Boolean?, val showVector: Boolean?,
val order: Int) val order: Int)
//</editor-fold>
//<editor-fold desc="4. Add handling annotation code to listParameters" defaultstate="collapsed">
/** /**
* List all parameters, (public var properties with a parameter annotation) * List all parameters, (public var properties with a parameter annotation)
*/ */
fun Any.listParameters(): List<Parameter> { fun Any.listParameters(): List<Parameter> {
return (this::class.memberProperties.filter { return (this::class.memberProperties.filter { property ->
!it.isConst && !property.isConst &&
it is KMutableProperty1<*, *> && property is KMutableProperty1<*, *> &&
it.visibility == KVisibility.PUBLIC && property.visibility == KVisibility.PUBLIC &&
it.annotations.map { it.annotationClass }.intersect(ParameterType.parameterAnnotationClasses).isNotEmpty() property.annotations.map { it.annotationClass }.intersect(ParameterType.parameterAnnotationClasses).isNotEmpty()
}.map { }.map { property ->
val annotations = it.annotations.filter { it.annotationClass in ParameterType.parameterAnnotationClasses } val annotations = property.annotations.filter { it.annotationClass in ParameterType.parameterAnnotationClasses }
var intRange: IntRange? = null var intRange: IntRange? = null
var doubleRange: ClosedRange<Double>? = null var doubleRange: ClosedRange<Double>? = null
var sizeRange: ClosedRange<Int>? = null
var order: Int = Integer.MAX_VALUE var order: Int = Integer.MAX_VALUE
var label = "" var label = ""
var precision: Int? = null var precision: Int? = null
@@ -199,15 +230,24 @@ fun Any.listParameters(): List<Parameter> {
invertY = it.invertY invertY = it.invertY
showVector = it.showVector showVector = it.showVector
} }
is DoubleListParameter -> {
label = it.label
order = it.order
doubleRange = it.low..it.high
precision = it.precision
sizeRange = it.minimumListLength..it.maximumListLength
}
} }
} }
Parameter( Parameter(
parameterType = type ?: error("no type"), parameterType = type ?: error("no type"),
property = it as KMutableProperty1<out Any, Any?>, property = property as KMutableProperty1<out Any, Any?>,
function = null, function = null,
label = label, label = label,
doubleRange = doubleRange, doubleRange = doubleRange,
vectorRange = vectorRange, vectorRange = vectorRange,
sizeRange = sizeRange,
intRange = intRange, intRange = intRange,
precision = precision, precision = precision,
showVector = showVector, showVector = showVector,
@@ -228,6 +268,7 @@ fun Any.listParameters(): List<Parameter> {
label = label, label = label,
doubleRange = null, doubleRange = null,
intRange = null, intRange = null,
sizeRange = null,
vectorRange = null, vectorRange = null,
precision = null, precision = null,
showVector = null, showVector = null,
@@ -236,6 +277,7 @@ fun Any.listParameters(): List<Parameter> {
) )
}).sortedBy { it.order } }).sortedBy { it.order }
} }
//</editor-fold>
fun Any.title() = this::class.findAnnotation<Description>()?.title fun Any.title() = this::class.findAnnotation<Description>()?.title

View File

@@ -28,20 +28,23 @@ val a = object {
@XYParameter("an XY parameter", order = 6) @XYParameter("an XY parameter", order = 6)
var xy = Vector2.ZERO var xy = Vector2.ZERO
@DoubleListParameter("a double list parameter", order = 7)
var dl = mutableListOf<Double>()
} }
object TestAnnotations : Spek({ object TestAnnotations : Spek({
describe("an annotated object") { describe("an annotated object") {
it("has listable parameters") { it("has listable parameters") {
val list = a.listParameters() val list = a.listParameters()
list.size `should be equal to` 7 list.size `should be equal to` 8
list[0].property?.name `should be equal to` "d" list[0].property?.name `should be equal to` "d"
list[0].parameterType `should be equal to` ParameterType.Double list[0].parameterType `should be equal to` ParameterType.Double
list[0].label `should be equal to` "a double scalar" list[0].label `should be equal to` "a double scalar"
list[0].doubleRange?.let { list[0].doubleRange?.let {
it.start shouldBeInRange 0.0 .. 0.0001 it.start shouldBeInRange 0.0..0.0001
it.endInclusive shouldBeInRange 0.999 .. 1.001 it.endInclusive shouldBeInRange 0.999..1.001
} }
list[0].precision `should be equal to` 3 list[0].precision `should be equal to` 3
@@ -68,7 +71,7 @@ object TestAnnotations : Spek({
invoking { invoking {
try { try {
list[3].function?.call(a) list[3].function?.call(a)
} catch(e: java.lang.reflect.InvocationTargetException) { } catch (e: java.lang.reflect.InvocationTargetException) {
/* this unpacks the exception that is wrapped in the ITExc */ /* this unpacks the exception that is wrapped in the ITExc */
throw(e.targetException) throw(e.targetException)
} }
@@ -85,6 +88,10 @@ object TestAnnotations : Spek({
list[6].parameterType `should be equal to` ParameterType.XY list[6].parameterType `should be equal to` ParameterType.XY
list[6].property?.name `should be equal to` "xy" list[6].property?.name `should be equal to` "xy"
list[6].label `should be equal to` "an XY parameter" list[6].label `should be equal to` "an XY parameter"
list[7].parameterType `should be equal to` ParameterType.DoubleList
list[7].property?.name `should be equal to` "dl"
list[7].label `should be equal to` "a double list parameter"
} }
} }
}) })