2022-07-23 11:24:37 +03:00
|
|
|
package center.sciprog.maps.scheme
|
2022-07-23 10:27:58 +03:00
|
|
|
|
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
import androidx.compose.runtime.mutableStateMapOf
|
|
|
|
import androidx.compose.runtime.snapshots.SnapshotStateMap
|
|
|
|
import androidx.compose.ui.graphics.Color
|
|
|
|
import androidx.compose.ui.graphics.drawscope.DrawScope
|
|
|
|
import androidx.compose.ui.graphics.painter.Painter
|
|
|
|
import androidx.compose.ui.graphics.vector.ImageVector
|
|
|
|
import androidx.compose.ui.unit.DpSize
|
|
|
|
import androidx.compose.ui.unit.dp
|
2022-07-23 11:24:37 +03:00
|
|
|
import center.sciprog.maps.scheme.SchemeFeature.Companion.defaultScaleRange
|
2022-07-23 10:27:58 +03:00
|
|
|
|
|
|
|
typealias FeatureId = String
|
|
|
|
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
public class SchemeFeaturesState internal constructor(
|
|
|
|
private val features: MutableMap<FeatureId, SchemeFeature>,
|
|
|
|
private val attributes: MutableMap<FeatureId, SnapshotStateMap<Attribute<out Any?>, in Any?>>,
|
|
|
|
) {
|
|
|
|
public interface Attribute<T>
|
2022-07-23 10:27:58 +03:00
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
public fun features(): Map<FeatureId, SchemeFeature> = features
|
2022-07-23 10:27:58 +03:00
|
|
|
|
|
|
|
|
|
|
|
private fun generateID(feature: SchemeFeature): FeatureId = "@feature[${feature.hashCode().toUInt()}]"
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
public fun addFeature(id: FeatureId?, feature: SchemeFeature): FeatureId {
|
2022-07-23 10:27:58 +03:00
|
|
|
val safeId = id ?: generateID(feature)
|
2022-09-17 10:32:28 +03:00
|
|
|
features[id ?: generateID(feature)] = feature
|
2022-07-23 10:27:58 +03:00
|
|
|
return safeId
|
|
|
|
}
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
public fun <T> setAttribute(id: FeatureId, key: Attribute<T>, value: T) {
|
|
|
|
attributes.getOrPut(id) { mutableStateMapOf() }[key] = value
|
|
|
|
}
|
|
|
|
|
|
|
|
@Suppress("UNCHECKED_CAST")
|
|
|
|
public fun <T> getAttribute(id: FeatureId, key: Attribute<T>): T? =
|
|
|
|
attributes[id]?.get(key)?.let { it as T }
|
|
|
|
|
|
|
|
@Suppress("UNCHECKED_CAST")
|
|
|
|
public fun <T> findAllWithAttribute(key: Attribute<T>, condition: (T) -> Boolean): Set<FeatureId> {
|
|
|
|
return attributes.filterValues {
|
|
|
|
condition(it[key] as T)
|
|
|
|
}.keys
|
|
|
|
}
|
|
|
|
|
|
|
|
public companion object {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build, but do not remember map feature state
|
|
|
|
*/
|
|
|
|
public fun build(
|
|
|
|
builder: SchemeFeaturesState.() -> Unit = {},
|
|
|
|
): SchemeFeaturesState = SchemeFeaturesState(
|
|
|
|
mutableStateMapOf(),
|
|
|
|
mutableStateMapOf()
|
|
|
|
).apply(builder)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build and remember map feature state
|
|
|
|
*/
|
|
|
|
@Composable
|
|
|
|
public fun remember(
|
|
|
|
builder: SchemeFeaturesState.() -> Unit = {},
|
|
|
|
): SchemeFeaturesState = androidx.compose.runtime.remember(builder) {
|
|
|
|
build(builder)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2022-07-23 10:27:58 +03:00
|
|
|
}
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
fun SchemeFeaturesState.background(
|
|
|
|
box: SchemeRectangle,
|
2022-07-23 10:27:58 +03:00
|
|
|
id: FeatureId? = null,
|
2022-09-17 10:32:28 +03:00
|
|
|
painter: @Composable () -> Painter,
|
2022-07-23 10:27:58 +03:00
|
|
|
): FeatureId = addFeature(
|
|
|
|
id,
|
2022-09-17 10:32:28 +03:00
|
|
|
SchemeBackgroundFeature(box, painter = painter)
|
2022-07-23 10:27:58 +03:00
|
|
|
)
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
fun SchemeFeaturesState.background(
|
|
|
|
width: Float,
|
|
|
|
height: Float,
|
2022-07-23 10:27:58 +03:00
|
|
|
offset: SchemeCoordinates = SchemeCoordinates(0f, 0f),
|
|
|
|
id: FeatureId? = null,
|
2022-09-17 10:32:28 +03:00
|
|
|
painter: @Composable () -> Painter,
|
2022-07-23 10:27:58 +03:00
|
|
|
): FeatureId {
|
2022-09-17 10:32:28 +03:00
|
|
|
val box = SchemeRectangle(
|
2022-07-23 10:27:58 +03:00
|
|
|
offset,
|
2022-09-17 10:32:28 +03:00
|
|
|
SchemeCoordinates(width + offset.x, height + offset.y)
|
2022-07-23 10:27:58 +03:00
|
|
|
)
|
2022-09-17 10:32:28 +03:00
|
|
|
return background(box, id, painter = painter)
|
2022-07-23 10:27:58 +03:00
|
|
|
}
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
fun SchemeFeaturesState.circle(
|
2022-07-23 10:27:58 +03:00
|
|
|
center: SchemeCoordinates,
|
|
|
|
scaleRange: FloatRange = defaultScaleRange,
|
|
|
|
size: Float = 5f,
|
|
|
|
color: Color = Color.Red,
|
|
|
|
id: FeatureId? = null,
|
|
|
|
) = addFeature(
|
|
|
|
id, SchemeCircleFeature(center, scaleRange, size, color)
|
|
|
|
)
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
fun SchemeFeaturesState.circle(
|
2022-07-23 10:27:58 +03:00
|
|
|
centerCoordinates: Pair<Number, Number>,
|
|
|
|
scaleRange: FloatRange = defaultScaleRange,
|
|
|
|
size: Float = 5f,
|
|
|
|
color: Color = Color.Red,
|
|
|
|
id: FeatureId? = null,
|
|
|
|
) = addFeature(
|
|
|
|
id, SchemeCircleFeature(centerCoordinates.toCoordinates(), scaleRange, size, color)
|
|
|
|
)
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
fun SchemeFeaturesState.draw(
|
2022-07-23 10:27:58 +03:00
|
|
|
position: Pair<Number, Number>,
|
|
|
|
scaleRange: FloatRange = defaultScaleRange,
|
|
|
|
id: FeatureId? = null,
|
|
|
|
drawFeature: DrawScope.() -> Unit,
|
|
|
|
) = addFeature(id, SchemeDrawFeature(position.toCoordinates(), scaleRange, drawFeature))
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
fun SchemeFeaturesState.line(
|
2022-07-23 10:27:58 +03:00
|
|
|
aCoordinates: Pair<Number, Number>,
|
|
|
|
bCoordinates: Pair<Number, Number>,
|
|
|
|
scaleRange: FloatRange = defaultScaleRange,
|
|
|
|
color: Color = Color.Red,
|
|
|
|
id: FeatureId? = null,
|
|
|
|
) = addFeature(id, SchemeLineFeature(aCoordinates.toCoordinates(), bCoordinates.toCoordinates(), scaleRange, color))
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
fun SchemeFeaturesState.text(
|
2022-07-23 10:27:58 +03:00
|
|
|
position: SchemeCoordinates,
|
|
|
|
text: String,
|
|
|
|
scaleRange: FloatRange = defaultScaleRange,
|
|
|
|
color: Color = Color.Red,
|
|
|
|
id: FeatureId? = null,
|
|
|
|
) = addFeature(id, SchemeTextFeature(position, text, scaleRange, color))
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
fun SchemeFeaturesState.text(
|
2022-07-23 10:27:58 +03:00
|
|
|
position: Pair<Number, Number>,
|
|
|
|
text: String,
|
|
|
|
scaleRange: FloatRange = defaultScaleRange,
|
|
|
|
color: Color = Color.Red,
|
|
|
|
id: FeatureId? = null,
|
|
|
|
) = addFeature(id, SchemeTextFeature(position.toCoordinates(), text, scaleRange, color))
|
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
fun SchemeFeaturesState.image(
|
2022-07-23 10:27:58 +03:00
|
|
|
position: Pair<Number, Number>,
|
|
|
|
image: ImageVector,
|
|
|
|
size: DpSize = DpSize(20.dp, 20.dp),
|
|
|
|
scaleRange: FloatRange = defaultScaleRange,
|
|
|
|
id: FeatureId? = null,
|
2022-09-17 10:32:28 +03:00
|
|
|
) = addFeature(id, SchemeImageFeature(position.toCoordinates(), image, size, scaleRange))
|
2022-07-23 10:27:58 +03:00
|
|
|
|
2022-09-17 10:32:28 +03:00
|
|
|
fun SchemeFeaturesState.group(
|
2022-07-23 10:27:58 +03:00
|
|
|
scaleRange: FloatRange = defaultScaleRange,
|
|
|
|
id: FeatureId? = null,
|
2022-09-17 10:32:28 +03:00
|
|
|
builder: SchemeFeaturesState.() -> Unit,
|
2022-07-23 10:27:58 +03:00
|
|
|
): FeatureId {
|
2022-09-17 10:32:28 +03:00
|
|
|
val groupBuilder = SchemeFeaturesState.build(builder)
|
|
|
|
val feature = SchemeFeatureGroup(groupBuilder.features(), scaleRange)
|
2022-07-23 10:27:58 +03:00
|
|
|
return addFeature(id, feature)
|
|
|
|
}
|