Refactored drag processing
This commit is contained in:
parent
26aaac2ecd
commit
5a1d3d701f
@ -7,6 +7,7 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PointMode
|
||||
import androidx.compose.ui.input.pointer.isPrimaryPressed
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.application
|
||||
import center.sciprog.maps.compose.*
|
||||
@ -58,14 +59,18 @@ fun App() {
|
||||
config = MapViewConfig(
|
||||
inferViewBoxFromFeatures = true,
|
||||
onViewChange = { centerCoordinates = focus },
|
||||
onDrag = { start, end ->
|
||||
if (start.focus.latitude.degrees.value in (pointTwo.first - 0.05)..(pointTwo.first + 0.05) &&
|
||||
dragHandle = { event, start, end ->
|
||||
if (!event.buttons.isPrimaryPressed) {
|
||||
true
|
||||
} else if (start.focus.latitude.degrees.value in (pointTwo.first - 0.05)..(pointTwo.first + 0.05) &&
|
||||
start.focus.longitude.degrees.value in (pointTwo.second - 0.05)..(pointTwo.second + 0.05)
|
||||
) {
|
||||
pointTwo = pointTwo.first + (end.focus.latitude - start.focus.latitude).degrees.value to
|
||||
pointTwo.second + (end.focus.longitude - start.focus.longitude).degrees.value
|
||||
false// returning false, because when we are dragging circle we don't want to drag map
|
||||
} else true
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
|
@ -3,6 +3,7 @@ package center.sciprog.maps.compose
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.PointerEvent
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import center.sciprog.maps.coordinates.*
|
||||
import kotlin.math.PI
|
||||
@ -10,16 +11,29 @@ import kotlin.math.log2
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
public fun interface DragHandle {
|
||||
/**
|
||||
* @param event - qualifiers of the event used for drag
|
||||
* @param start - is a point where drag begins, end is a point where drag ends
|
||||
* @param end - end point of the drag
|
||||
*
|
||||
* @return true if default event processors should be used after this one
|
||||
*/
|
||||
public fun drag(event: PointerEvent, start: MapViewPoint, end: MapViewPoint): Boolean
|
||||
|
||||
public companion object {
|
||||
public val BYPASS: DragHandle = DragHandle { _, _, _ -> true }
|
||||
}
|
||||
}
|
||||
|
||||
//TODO consider replacing by modifier
|
||||
/**
|
||||
* @param onDrag - returns true if you want to drag a map and false, if you want to make map stationary.
|
||||
* start - is a point where drag begins, end is a point where drag ends
|
||||
*/
|
||||
public data class MapViewConfig(
|
||||
val zoomSpeed: Double = 1.0 / 3.0,
|
||||
val inferViewBoxFromFeatures: Boolean = false,
|
||||
val onClick: MapViewPoint.() -> Unit = {},
|
||||
val onDrag: (start: MapViewPoint, end: MapViewPoint) -> Boolean = { _, _ -> true },
|
||||
val onClick: MapViewPoint.(PointerEvent) -> Unit = {},
|
||||
val dragHandle: DragHandle = DragHandle.BYPASS,
|
||||
val onViewChange: MapViewPoint.() -> Unit = {},
|
||||
val onSelect: (GmcRectangle) -> Unit = {},
|
||||
val zoomOnSelect: Boolean = true,
|
||||
|
@ -80,9 +80,14 @@ public actual fun MapView(
|
||||
}
|
||||
}
|
||||
|
||||
val zoom: Int by derivedStateOf { floor(viewPoint.zoom).toInt() }
|
||||
val zoom: Int by derivedStateOf {
|
||||
require(viewPoint.zoom in 1.0..18.0) { "Zoom value of ${viewPoint.zoom} is not valid" }
|
||||
floor(viewPoint.zoom).toInt()
|
||||
}
|
||||
|
||||
val tileScale: Double by derivedStateOf { 2.0.pow(viewPoint.zoom - zoom) }
|
||||
val tileScale: Double by derivedStateOf {
|
||||
2.0.pow(viewPoint.zoom - zoom)
|
||||
}
|
||||
|
||||
val mapTiles = remember { mutableStateListOf<MapTile>() }
|
||||
|
||||
@ -109,61 +114,75 @@ public actual fun MapView(
|
||||
fun Offset.toDpOffset() = DpOffset(x.toDp(), y.toDp())
|
||||
|
||||
val event: PointerEvent = awaitPointerEvent()
|
||||
event.changes.forEach { change ->
|
||||
if (event.buttons.isPrimaryPressed) {
|
||||
//Evaluating selection frame
|
||||
if (event.keyboardModifiers.isShiftPressed) {
|
||||
selectRect = Rect(change.position, change.position)
|
||||
drag(change.id) { dragChange ->
|
||||
selectRect?.let { rect ->
|
||||
val offset = dragChange.position
|
||||
selectRect = Rect(
|
||||
min(offset.x, rect.left),
|
||||
min(offset.y, rect.top),
|
||||
max(offset.x, rect.right),
|
||||
max(offset.y, rect.bottom)
|
||||
)
|
||||
}
|
||||
}
|
||||
selectRect?.let { rect ->
|
||||
//Use selection override if it is defined
|
||||
val gmcBox = GmcRectangle(
|
||||
rect.topLeft.toDpOffset().toGeodetic(),
|
||||
rect.bottomRight.toDpOffset().toGeodetic()
|
||||
)
|
||||
config.onSelect(gmcBox)
|
||||
if (config.zoomOnSelect) {
|
||||
val newViewPoint = gmcBox.computeViewPoint(mapTileProvider).invoke(canvasSize)
|
||||
|
||||
config.onViewChange(newViewPoint)
|
||||
viewPointInternal = newViewPoint
|
||||
}
|
||||
selectRect = null
|
||||
}
|
||||
} else {
|
||||
val dragStart = change.position
|
||||
val dpPos = DpOffset(dragStart.x.toDp(), dragStart.y.toDp())
|
||||
config.onClick(MapViewPoint(dpPos.toGeodetic(), viewPoint.zoom))
|
||||
drag(change.id) { dragChange ->
|
||||
val dragAmount = dragChange.position - dragChange.previousPosition
|
||||
val dpStart = DpOffset(
|
||||
dragChange.previousPosition.x.toDp(),
|
||||
dragChange.previousPosition.y.toDp()
|
||||
)
|
||||
val dpEnd = DpOffset(dragChange.position.x.toDp(), dragChange.position.y.toDp())
|
||||
if (!config.onDrag(
|
||||
MapViewPoint(dpStart.toGeodetic(), viewPoint.zoom),
|
||||
MapViewPoint(dpEnd.toGeodetic(), viewPoint.zoom)
|
||||
)
|
||||
) return@drag
|
||||
val newViewPoint = viewPoint.move(
|
||||
-dragAmount.x.toDp().value / tileScale,
|
||||
+dragAmount.y.toDp().value / tileScale
|
||||
)
|
||||
config.onViewChange(newViewPoint)
|
||||
viewPointInternal = newViewPoint
|
||||
}
|
||||
event.changes.forEach { change ->
|
||||
val dragStart = change.position
|
||||
val dpPos = DpOffset(dragStart.x.toDp(), dragStart.y.toDp())
|
||||
|
||||
//start selection
|
||||
if (event.buttons.isPrimaryPressed && event.keyboardModifiers.isShiftPressed) {
|
||||
selectRect = Rect(change.position, change.position)
|
||||
}
|
||||
|
||||
drag(change.id) { dragChange ->
|
||||
val dragAmount = dragChange.position - dragChange.previousPosition
|
||||
val dpStart = DpOffset(
|
||||
dragChange.previousPosition.x.toDp(),
|
||||
dragChange.previousPosition.y.toDp()
|
||||
)
|
||||
val dpEnd = DpOffset(dragChange.position.x.toDp(), dragChange.position.y.toDp())
|
||||
|
||||
if (
|
||||
!config.dragHandle.drag(
|
||||
event,
|
||||
MapViewPoint(dpStart.toGeodetic(), viewPoint.zoom),
|
||||
MapViewPoint(dpEnd.toGeodetic(), viewPoint.zoom)
|
||||
)
|
||||
) {
|
||||
//clear selection just in case
|
||||
selectRect = null
|
||||
return@drag
|
||||
}
|
||||
|
||||
if (event.buttons.isPrimaryPressed) {
|
||||
//Evaluating selection frame
|
||||
selectRect?.let { rect ->
|
||||
val offset = dragChange.position
|
||||
selectRect = Rect(
|
||||
min(offset.x, rect.left),
|
||||
min(offset.y, rect.top),
|
||||
max(offset.x, rect.right),
|
||||
max(offset.y, rect.bottom)
|
||||
)
|
||||
return@drag
|
||||
}
|
||||
|
||||
config.onClick(MapViewPoint(dpPos.toGeodetic(), viewPoint.zoom), event)
|
||||
|
||||
val newViewPoint = viewPoint.move(
|
||||
-dragAmount.x.toDp().value / tileScale,
|
||||
+dragAmount.y.toDp().value / tileScale
|
||||
)
|
||||
config.onViewChange(newViewPoint)
|
||||
viewPointInternal = newViewPoint
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate selection
|
||||
selectRect?.let { rect ->
|
||||
//Use selection override if it is defined
|
||||
val gmcBox = GmcRectangle(
|
||||
rect.topLeft.toDpOffset().toGeodetic(),
|
||||
rect.bottomRight.toDpOffset().toGeodetic()
|
||||
)
|
||||
config.onSelect(gmcBox)
|
||||
if (config.zoomOnSelect) {
|
||||
val newViewPoint = gmcBox.computeViewPoint(mapTileProvider).invoke(canvasSize)
|
||||
|
||||
config.onViewChange(newViewPoint)
|
||||
viewPointInternal = newViewPoint
|
||||
}
|
||||
selectRect = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user