0.3.0 #23
@ -4,7 +4,6 @@ import androidx.compose.foundation.Canvas
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.key
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@ -19,9 +18,13 @@ import androidx.compose.ui.text.drawText
|
|||||||
import androidx.compose.ui.text.rememberTextMeasurer
|
import androidx.compose.ui.text.rememberTextMeasurer
|
||||||
import androidx.compose.ui.unit.DpRect
|
import androidx.compose.ui.unit.DpRect
|
||||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.sample
|
||||||
import space.kscience.attributes.Attributes
|
import space.kscience.attributes.Attributes
|
||||||
import space.kscience.attributes.plus
|
import space.kscience.attributes.plus
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An extension of [DrawScope] to include map-specific features
|
* An extension of [DrawScope] to include map-specific features
|
||||||
@ -76,22 +79,23 @@ public class ComposeFeatureDrawScope<T : Any>(
|
|||||||
/**
|
/**
|
||||||
* Create a canvas with extended functionality (e.g., drawing text)
|
* Create a canvas with extended functionality (e.g., drawing text)
|
||||||
*/
|
*/
|
||||||
|
@OptIn(FlowPreview::class)
|
||||||
@Composable
|
@Composable
|
||||||
public fun <T : Any> FeatureCanvas(
|
public fun <T : Any> FeatureCanvas(
|
||||||
state: CanvasState<T>,
|
state: CanvasState<T>,
|
||||||
featureFlow: StateFlow<Map<String, Feature<T>>>,
|
featureFlow: StateFlow<Map<String, Feature<T>>>,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
sampleDuration: Duration = 20.milliseconds,
|
||||||
draw: FeatureDrawScope<T>.() -> Unit = {},
|
draw: FeatureDrawScope<T>.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val textMeasurer = rememberTextMeasurer(0)
|
val textMeasurer = rememberTextMeasurer(0)
|
||||||
|
|
||||||
val features by featureFlow.collectAsState()
|
val features by featureFlow.sample(sampleDuration).collectAsState(featureFlow.value)
|
||||||
|
|
||||||
val painterCache = key(features) {
|
val painterCache = features.values
|
||||||
features.values
|
|
||||||
.filterIsInstance<PainterFeature<T>>()
|
.filterIsInstance<PainterFeature<T>>()
|
||||||
.associateWith { it.getPainter() }
|
.associateWith { it.getPainter() }
|
||||||
}
|
|
||||||
|
|
||||||
Canvas(modifier) {
|
Canvas(modifier) {
|
||||||
if (state.canvasSize != size.toDpSize()) {
|
if (state.canvasSize != size.toDpSize()) {
|
||||||
@ -102,12 +106,13 @@ public fun <T : Any> FeatureCanvas(
|
|||||||
|
|
||||||
val attributesCache = mutableMapOf<List<String>, Attributes>()
|
val attributesCache = mutableMapOf<List<String>, Attributes>()
|
||||||
|
|
||||||
fun computeGroupAttributes(path: List<String>): Attributes = attributesCache.getOrPut(path){
|
fun computeGroupAttributes(path: List<String>): Attributes = attributesCache.getOrPut(path) {
|
||||||
if (path.isEmpty()) return Attributes.EMPTY
|
if (path.isEmpty()) return Attributes.EMPTY
|
||||||
else if (path.size == 1) {
|
else if (path.size == 1) {
|
||||||
features[path.first()]?.attributes ?: Attributes.EMPTY
|
features[path.first()]?.attributes ?: Attributes.EMPTY
|
||||||
} else {
|
} else {
|
||||||
computeGroupAttributes(path.dropLast(1)) + (features[path.first()]?.attributes ?: Attributes.EMPTY)
|
computeGroupAttributes(path.dropLast(1)) + (features[path.first()]?.attributes
|
||||||
|
?: Attributes.EMPTY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,10 +46,12 @@ public interface FeatureBuilder<T : Any> {
|
|||||||
public val space: CoordinateSpace<T>
|
public val space: CoordinateSpace<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add or replace feature. If [id] is null, then a unique id is genertated
|
* Add or replace feature. If [id] is null, then a unique id is generated
|
||||||
*/
|
*/
|
||||||
public fun <F : Feature<T>> feature(id: String?, feature: F): FeatureRef<T, F>
|
public fun <F : Feature<T>> feature(id: String?, feature: F): FeatureRef<T, F>
|
||||||
|
|
||||||
|
public fun putFeatures(features: Map<String, Feature<T>?>)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update existing feature if it is present and is of type [F]
|
* Update existing feature if it is present and is of type [F]
|
||||||
*/
|
*/
|
||||||
@ -89,6 +91,18 @@ public class FeatureStore<T : Any>(
|
|||||||
return FeatureRef(this, safeId)
|
return FeatureRef(this, safeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override fun putFeatures(features: Map<String, Feature<T>?>) {
|
||||||
|
_featureFlow.value = _featureFlow.value.toMutableMap().apply {
|
||||||
|
features.forEach { (key, value) ->
|
||||||
|
if (value == null) {
|
||||||
|
remove(key)
|
||||||
|
} else {
|
||||||
|
put(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <F : Feature<T>> updateFeature(id: String, block: (F?) -> F): FeatureRef<T, F> =
|
override fun <F : Feature<T>> updateFeature(id: String, block: (F?) -> F): FeatureRef<T, F> =
|
||||||
feature(id, block(features[id] as? F))
|
feature(id, block(features[id] as? F))
|
||||||
@ -159,10 +173,13 @@ public data class FeatureGroup<T : Any> internal constructor(
|
|||||||
override fun withAttributes(modify: Attributes.() -> Attributes): FeatureGroup<T> =
|
override fun withAttributes(modify: Attributes.() -> Attributes): FeatureGroup<T> =
|
||||||
FeatureGroup(store, groupId, modify(attributes))
|
FeatureGroup(store, groupId, modify(attributes))
|
||||||
|
|
||||||
|
|
||||||
override fun <F : Feature<T>> feature(id: String?, feature: F): FeatureRef<T, F> =
|
override fun <F : Feature<T>> feature(id: String?, feature: F): FeatureRef<T, F> =
|
||||||
store.feature("$groupId/${id ?: generateFeatureId(feature)}", feature)
|
store.feature("$groupId/${id ?: generateFeatureId(feature)}", feature)
|
||||||
|
|
||||||
|
public override fun putFeatures(features: Map<String, Feature<T>?>) {
|
||||||
|
store.putFeatures(features.mapKeys { "$groupId/${it.key}" })
|
||||||
|
}
|
||||||
|
|
||||||
override fun <F : Feature<T>> updateFeature(id: String, block: (F?) -> F): FeatureRef<T, F> =
|
override fun <F : Feature<T>> updateFeature(id: String, block: (F?) -> F): FeatureRef<T, F> =
|
||||||
store.updateFeature("$groupId/$id", block)
|
store.updateFeature("$groupId/$id", block)
|
||||||
|
|
||||||
|
@ -98,13 +98,6 @@ public fun <T : Any> FeatureDrawScope<T>.drawFeature(
|
|||||||
|
|
||||||
is FeatureGroup -> {
|
is FeatureGroup -> {
|
||||||
//ignore groups
|
//ignore groups
|
||||||
// feature.features.values.forEach {
|
|
||||||
// drawFeature(
|
|
||||||
// it.withAttributes {
|
|
||||||
// feature.attributes + this
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PathFeature -> {
|
is PathFeature -> {
|
||||||
|
Loading…
Reference in New Issue
Block a user