Cleanup drag
This commit is contained in:
parent
42dbbeea58
commit
572adf041f
@ -76,22 +76,19 @@ fun App() {
|
||||
line(drag3, drag1, id = "connection3", color = Color.Magenta)
|
||||
}
|
||||
|
||||
rectangle(drag1, size = DpSize(10.dp, 10.dp)).draggable { _, _, end ->
|
||||
drag1 = end.focus
|
||||
rectangle(drag1, size = DpSize(10.dp, 10.dp)).draggable { _, end ->
|
||||
drag1 = end
|
||||
updateLine()
|
||||
true
|
||||
}
|
||||
|
||||
rectangle(drag2, size = DpSize(10.dp, 10.dp)).draggable { _, _, end ->
|
||||
drag2 = end.focus
|
||||
rectangle(drag2, size = DpSize(10.dp, 10.dp)).draggable { _, end ->
|
||||
drag2 = end
|
||||
updateLine()
|
||||
true
|
||||
}
|
||||
|
||||
rectangle(drag3, size = DpSize(10.dp, 10.dp)).draggable { _, _, end ->
|
||||
drag3 = end.focus
|
||||
rectangle(drag3, size = DpSize(10.dp, 10.dp)).draggable { _, end ->
|
||||
drag3 = end
|
||||
updateLine()
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -87,17 +87,24 @@ public fun MapView(
|
||||
val viewPointOverride: MapViewPoint = remember(initialViewPoint, initialRectangle) {
|
||||
initialViewPoint
|
||||
?: initialRectangle?.computeViewPoint(mapTileProvider)
|
||||
?: featureState.features.values.computeBoundingBox(GmcCoordinateSpace,1f)?.computeViewPoint(mapTileProvider)
|
||||
?: featureState.features.values.computeBoundingBox(GmcCoordinateSpace, 1f)
|
||||
?.computeViewPoint(mapTileProvider)
|
||||
?: MapViewPoint.globe
|
||||
}
|
||||
|
||||
val featureDrag: DragHandle<Gmc> = DragHandle.withPrimaryButton { event, start: ViewPoint<Gmc>, end: ViewPoint<Gmc> ->
|
||||
val featureDrag: DragHandle<Gmc> = DragHandle.withPrimaryButton { event, start, end ->
|
||||
featureState.forEachWithAttribute(DraggableAttribute) { _, handle ->
|
||||
//TODO add safety
|
||||
handle as DragHandle<Gmc>
|
||||
if (!handle.handle(event, start, end)) return@withPrimaryButton false
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(handle as DragHandle<Gmc>)
|
||||
.handle(event, start, end)
|
||||
.takeIf { !it.handleNext }
|
||||
?.let {
|
||||
//we expect it already have no bypass
|
||||
return@withPrimaryButton it
|
||||
}
|
||||
}
|
||||
true
|
||||
//bypass
|
||||
DragResult(end)
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,7 +127,7 @@ public actual fun MapView(
|
||||
)
|
||||
}
|
||||
|
||||
featuresState.features.values.filter { viewPoint.zoom in it.zoomRange }.sortedBy { it.depth }.forEach { feature ->
|
||||
featuresState.features.values.filter { viewPoint.zoom in it.zoomRange }.sortedBy { it.z }.forEach { feature ->
|
||||
drawFeature(state, painterCache, feature)
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ package center.sciprog.maps.features
|
||||
import androidx.compose.runtime.mutableStateMapOf
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
public object DepthAttribute : Feature.Attribute<Float>
|
||||
public object ZAttribute : Feature.Attribute<Float>
|
||||
|
||||
public object DraggableAttribute : Feature.Attribute<DragHandle<*>>
|
||||
public object DraggableAttribute : Feature.Attribute<DragHandle<Any>>
|
||||
|
||||
public object SelectableAttribute : Feature.Attribute<(FeatureId<*>, SelectableFeature<*>) -> Unit>
|
||||
|
||||
@ -46,8 +46,8 @@ public class AttributeMap {
|
||||
override fun toString(): String = "AttributeMap(value=${map.entries})"
|
||||
}
|
||||
|
||||
public var Feature<*>.depth: Float
|
||||
get() = attributes[DepthAttribute] ?: 0f
|
||||
public var Feature<*>.z: Float
|
||||
get() = attributes[ZAttribute] ?: 0f
|
||||
set(value) {
|
||||
attributes[DepthAttribute] = value
|
||||
attributes[ZAttribute] = value
|
||||
}
|
@ -3,7 +3,13 @@ package center.sciprog.maps.features
|
||||
import androidx.compose.ui.input.pointer.PointerEvent
|
||||
import androidx.compose.ui.input.pointer.isPrimaryPressed
|
||||
|
||||
public fun interface DragHandle<T: Any>{
|
||||
/**
|
||||
* @param result - the endpoint of the drag to perform constrained drag
|
||||
* @param handleNext - if false do not evaluate subsequent drag handles
|
||||
*/
|
||||
public data class DragResult<T : Any>(val result: ViewPoint<T>, val handleNext: Boolean = true)
|
||||
|
||||
public fun interface DragHandle<T : Any> {
|
||||
/**
|
||||
* @param event - qualifiers of the event used for drag
|
||||
* @param start - is a point where drag begins, end is a point where drag ends
|
||||
@ -11,32 +17,36 @@ public fun interface DragHandle<T: Any>{
|
||||
*
|
||||
* @return true if default event processors should be used after this one
|
||||
*/
|
||||
public fun handle(event: PointerEvent, start: ViewPoint<T>, end: ViewPoint<T>): Boolean
|
||||
public fun handle(event: PointerEvent, start: ViewPoint<T>, end: ViewPoint<T>): DragResult<T>
|
||||
|
||||
public companion object {
|
||||
public fun <T: Any> bypass(): DragHandle<T> = DragHandle<T> { _, _, _ -> true }
|
||||
public fun <T : Any> bypass(): DragHandle<T> = DragHandle<T> { _, _, end -> DragResult(end) }
|
||||
|
||||
/**
|
||||
* Process only events with primary button pressed
|
||||
*/
|
||||
public fun <T: Any> withPrimaryButton(
|
||||
block: (event: PointerEvent, start: ViewPoint<T>, end: ViewPoint<T>) -> Boolean,
|
||||
public fun <T : Any> withPrimaryButton(
|
||||
block: (event: PointerEvent, start: ViewPoint<T>, end: ViewPoint<T>) -> DragResult<T>,
|
||||
): DragHandle<T> = DragHandle { event, start, end ->
|
||||
if (event.buttons.isPrimaryPressed) {
|
||||
block(event, start, end)
|
||||
} else {
|
||||
true
|
||||
DragResult(end)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine several handles into one
|
||||
*/
|
||||
public fun <T: Any> combine(vararg handles: DragHandle<T>): DragHandle<T> = DragHandle { event, start, end ->
|
||||
public fun <T : Any> combine(vararg handles: DragHandle<T>): DragHandle<T> = DragHandle { event, start, end ->
|
||||
var current: ViewPoint<T> = end
|
||||
handles.forEach {
|
||||
if (!it.handle(event, start, end)) return@DragHandle false
|
||||
val result = it.handle(event, start, current)
|
||||
if (!result.handleNext) return@DragHandle result else {
|
||||
current = result.result
|
||||
}
|
||||
}
|
||||
return@DragHandle true
|
||||
return@DragHandle DragResult(current)
|
||||
}
|
||||
}
|
||||
}
|
@ -44,23 +44,33 @@ public class FeaturesState<T : Any>(public val coordinateSpace: CoordinateSpace<
|
||||
|
||||
|
||||
public fun <F : Feature<T>, V> setAttribute(id: FeatureId<F>, key: Feature.Attribute<V>, value: V?) {
|
||||
getFeature(id).attributes.set(key, value)
|
||||
getFeature(id).attributes[key] = value
|
||||
}
|
||||
|
||||
//TODO use context receiver for that
|
||||
/**
|
||||
* Add drag to this feature
|
||||
*
|
||||
* @param constraint optional drag constraint
|
||||
*
|
||||
* TODO use context receiver for that
|
||||
*/
|
||||
public fun FeatureId<DraggableFeature<T>>.draggable(
|
||||
//TODO add constraints
|
||||
callback: DragHandle<T> = DragHandle.bypass(),
|
||||
constraint: ((T) -> T)? = null,
|
||||
callback: ((start: T, end: T) -> Unit) = { _, _ -> },
|
||||
) {
|
||||
val handle = DragHandle.withPrimaryButton<T> { event, start, end ->
|
||||
val feature = featureMap[id] as? DraggableFeature ?: return@withPrimaryButton true
|
||||
val boundingBox = feature.getBoundingBox(start.zoom) ?: return@withPrimaryButton true
|
||||
if (start.focus in boundingBox) {
|
||||
feature(id, feature.withCoordinates(end.focus))
|
||||
callback.handle(event, start, end)
|
||||
false
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val handle = DragHandle.withPrimaryButton<Any> { _, start, end ->
|
||||
val startPosition = start.focus as T
|
||||
val endPosition = end.focus as T
|
||||
val feature = featureMap[id] as? DraggableFeature ?: return@withPrimaryButton DragResult(end)
|
||||
val boundingBox = feature.getBoundingBox(start.zoom) ?: return@withPrimaryButton DragResult(end)
|
||||
if (startPosition in boundingBox) {
|
||||
val finalPosition = constraint?.invoke(endPosition) ?: endPosition
|
||||
feature(id, feature.withCoordinates(finalPosition))
|
||||
callback(startPosition, finalPosition)
|
||||
DragResult(ViewPoint(finalPosition, end.zoom), false)
|
||||
} else {
|
||||
true
|
||||
DragResult(end, true)
|
||||
}
|
||||
}
|
||||
setAttribute(this, DraggableAttribute, handle)
|
||||
@ -98,11 +108,14 @@ public class FeaturesState<T : Any>(public val coordinateSpace: CoordinateSpace<
|
||||
// }.keys
|
||||
// }
|
||||
|
||||
/**
|
||||
* Process all features with a given attribute from the one with highest [z] to lowest
|
||||
*/
|
||||
public inline fun <A> forEachWithAttribute(
|
||||
key: Feature.Attribute<A>,
|
||||
block: (id: FeatureId<*>, attributeValue: A) -> Unit,
|
||||
) {
|
||||
featureMap.forEach { (id, feature) ->
|
||||
featureMap.entries.sortedByDescending { it.value.z }.forEach { (id, feature) ->
|
||||
feature.attributes[key]?.let {
|
||||
block(FeatureId<Feature<T>>(id), it)
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package center.sciprog.maps.features
|
||||
/**
|
||||
* @param T type of coordinates used for the view point
|
||||
*/
|
||||
public interface ViewPoint<T: Any> {
|
||||
public interface ViewPoint<out T: Any> {
|
||||
public val focus: T
|
||||
public val zoom: Float
|
||||
}
|
@ -44,13 +44,13 @@ public fun <T : Any> Modifier.mapControls(
|
||||
val dpEnd = dragChange.position.toDpOffset()
|
||||
|
||||
//apply drag handle and check if it prohibits the drag even propagation
|
||||
if (selectionStart == null && !config.dragHandle.handle(
|
||||
if (selectionStart == null) {
|
||||
val dragResult = config.dragHandle.handle(
|
||||
event,
|
||||
space.ViewPoint(dpStart.toCoordinates(), viewPoint.zoom),
|
||||
space.ViewPoint(dpEnd.toCoordinates(), viewPoint.zoom)
|
||||
)
|
||||
) {
|
||||
return@drag
|
||||
if(!dragResult.handleNext) return@drag
|
||||
}
|
||||
|
||||
if (event.buttons.isPrimaryPressed) {
|
||||
|
@ -26,7 +26,7 @@ fun FeaturesState<XY>.background(
|
||||
return feature(
|
||||
id,
|
||||
ScalableImageFeature(coordinateSpace, box, painter = painter).apply {
|
||||
depth = -100f
|
||||
z = -100f
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ public fun SchemeView(
|
||||
clipRect {
|
||||
featuresState.features.values
|
||||
.filter { viewPoint.zoom in it.zoomRange }
|
||||
.sortedBy { it.depth }
|
||||
.sortedBy { it.z }
|
||||
.forEach { background ->
|
||||
drawFeature(state, painterCache, background)
|
||||
}
|
||||
@ -139,10 +139,12 @@ public fun SchemeView(
|
||||
DragHandle.withPrimaryButton { event, start: ViewPoint<XY>, end: ViewPoint<XY> ->
|
||||
featureState.forEachWithAttribute(DraggableAttribute) { _, handle ->
|
||||
//TODO add safety
|
||||
handle as DragHandle<XY>
|
||||
if (!handle.handle(event, start, end)) return@withPrimaryButton false
|
||||
(handle as DragHandle<XY>)
|
||||
.handle(event, start, end)
|
||||
.takeIf { !it.handleNext }
|
||||
?.let { return@withPrimaryButton it }
|
||||
}
|
||||
true
|
||||
DragResult(end)
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user