Add helpers for converting points/rects between view coordinate systems
This commit is contained in:
parent
51528c4cbe
commit
a55cd950d0
|
@ -7,6 +7,8 @@ package net.shadowfacts.cacao.geometry
|
|||
*/
|
||||
data class Rect(val left: Double, val top: Double, val width: Double, val height: Double) {
|
||||
|
||||
constructor(origin: Point, size: Size): this(origin.x, origin.y, size.width, size.height)
|
||||
|
||||
val right: Double by lazy {
|
||||
left + width
|
||||
}
|
||||
|
|
|
@ -3,11 +3,9 @@ package net.shadowfacts.cacao.view
|
|||
import com.mojang.blaze3d.platform.GlStateManager
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.cacao.LayoutVariable
|
||||
import net.shadowfacts.cacao.geometry.Axis
|
||||
import net.shadowfacts.cacao.geometry.AxisPosition
|
||||
import net.shadowfacts.cacao.geometry.Rect
|
||||
import net.shadowfacts.cacao.geometry.Size
|
||||
import net.shadowfacts.cacao.geometry.*
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.util.LowestCommonAncestor
|
||||
import net.shadowfacts.cacao.util.RenderHelper
|
||||
import no.birkett.kiwi.Constraint
|
||||
import no.birkett.kiwi.Solver
|
||||
|
@ -214,4 +212,47 @@ open class View {
|
|||
*/
|
||||
open fun drawContent() {}
|
||||
|
||||
/**
|
||||
* Converts the given point in this view's coordinate system to the coordinate system of another view or the window.
|
||||
*
|
||||
* @param point The point to convert, in the coordinate system of this view.
|
||||
* @param to The view to convert to. If `null`, it will be converted to the window's coordinate system.
|
||||
* @return The point in the coordinate system of the [to] view.
|
||||
*/
|
||||
fun convert(point: Point, to: View?): Point {
|
||||
if (to != null) {
|
||||
val ancestor = LowestCommonAncestor.find(this, to, View::superview)
|
||||
@Suppress("NAME_SHADOWING") var point = point
|
||||
|
||||
// Convert up to the LCA
|
||||
var view: View? = this
|
||||
while (view != null && view != ancestor) {
|
||||
point = Point(point.x + view.frame.left, point.y + view.frame.top)
|
||||
view = view.superview
|
||||
}
|
||||
|
||||
// Convert back down to the other view
|
||||
view = to
|
||||
while (view != null && view != ancestor) {
|
||||
point = Point(point.x - view.frame.left, point.y - view.frame.top)
|
||||
view = view.superview
|
||||
}
|
||||
|
||||
return point
|
||||
} else {
|
||||
return Point(leftAnchor.value + point.x, topAnchor.value + point.y)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given rectangle in this view's coordinate system to the coordinate system of another view or the window.
|
||||
*
|
||||
* @param rect The rectangle to convert, in the coordinate system of this view.
|
||||
* @param to The view to convert to. If `null`, it will be converted to the window's coordinate system.
|
||||
* @return The rectangle in the coordinate system of the [to] view.
|
||||
*/
|
||||
fun convert(rect: Rect, to: View?): Rect {
|
||||
return Rect(convert(rect.origin, to), rect.size)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package net.shadowfacts.cacao
|
||||
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.geometry.Rect
|
||||
import net.shadowfacts.cacao.view.View
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class CoordinateConversionTests {
|
||||
|
||||
lateinit var window: Window
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
window = Window()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConvertToParent() {
|
||||
val a = window.addView(View().apply {
|
||||
frame = Rect(0.0, 0.0, 100.0, 100.0)
|
||||
})
|
||||
val b = a.addSubview(View().apply {
|
||||
frame = Rect(25.0, 25.0, 50.0, 50.0)
|
||||
})
|
||||
|
||||
assertEquals(Point(25.0, 25.0), b.convert(Point(0.0, 0.0), to = a))
|
||||
assertEquals(Point(75.0, 75.0), b.convert(Point(50.0, 50.0), to = a))
|
||||
assertEquals(Rect(25.0, 25.0, 50.0, 50.0), b.convert(Rect(0.0, 0.0, 50.0, 50.0), to = a))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConvertToSibling() {
|
||||
val root = window.addView(View().apply {
|
||||
frame = Rect(0.0, 0.0, 200.0, 200.0)
|
||||
})
|
||||
val a = root.addSubview(View().apply {
|
||||
frame = Rect(25.0, 25.0, 50.0, 50.0)
|
||||
})
|
||||
val b = root.addSubview(View().apply {
|
||||
frame = Rect(75.0, 75.0, 50.0, 50.0)
|
||||
})
|
||||
|
||||
assertEquals(Point(-50.0, -50.0), a.convert(Point(0.0, 0.0), to = b))
|
||||
assertEquals(Point(100.0, 100.0), b.convert(Point(50.0, 50.0), to = a))
|
||||
assertEquals(Rect(50.0, 50.0, 50.0, 50.0), b.convert(Rect(0.0, 0.0, 50.0, 50.0), to = a))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConvertBetweenSubtrees() {
|
||||
val root = window.addView(View().apply {
|
||||
frame = Rect(0.0, 0.0, 200.0, 100.0)
|
||||
})
|
||||
val a = root.addSubview(View().apply {
|
||||
frame = Rect(0.0, 0.0, 100.0, 100.0)
|
||||
})
|
||||
val b = root.addSubview(View().apply {
|
||||
frame = Rect(100.0, 0.0, 100.0, 100.0)
|
||||
})
|
||||
val c = a.addSubview(View().apply {
|
||||
frame = Rect(0.0, 0.0, 50.0, 50.0)
|
||||
})
|
||||
val d = b.addSubview(View().apply {
|
||||
frame = Rect(0.0, 0.0, 50.0, 50.0)
|
||||
})
|
||||
|
||||
assertEquals(Point(-100.0, 0.0), c.convert(Point(0.0, 0.0), to = b))
|
||||
assertEquals(Point(-50.0, 50.0), c.convert(Point(50.0, 50.0), to = d))
|
||||
assertEquals(Rect(100.0, 0.0, 50.0, 50.0), d.convert(Rect(0.0, 0.0, 50.0, 50.0), to = c))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConvertBetweenTopLevelViews() {
|
||||
val a = window.addView(View().apply {
|
||||
frame = Rect(0.0, 0.0, 100.0, 100.0)
|
||||
})
|
||||
val b = window.addView(View().apply {
|
||||
frame = Rect(100.0, 100.0, 100.0, 100.0)
|
||||
})
|
||||
|
||||
assertEquals(Point(0.0, 0.0), a.convert(Point(100.0, 100.0), to = b))
|
||||
assertEquals(Point(200.0, 200.0), b.convert(Point(100.0, 100.0), to = a))
|
||||
assertEquals(Rect(100.0, 100.0, 100.0, 100.0), b.convert(Rect(0.0, 0.0, 100.0, 100.0), to = a))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConvertBetweenTopLevelSubtrees() {
|
||||
val a = window.addView(View().apply {
|
||||
frame = Rect(0.0, 0.0, 100.0, 100.0)
|
||||
})
|
||||
val b = window.addView(View().apply {
|
||||
frame = Rect(100.0, 100.0, 100.0, 100.0)
|
||||
})
|
||||
val c = a.addSubview(View().apply {
|
||||
frame = Rect(25.0, 25.0, 50.0, 50.0)
|
||||
})
|
||||
val d = b.addSubview(View().apply {
|
||||
frame = Rect(25.0, 25.0, 50.0, 50.0)
|
||||
})
|
||||
|
||||
assertEquals(Point(-50.0, -50.0), c.convert(Point(50.0, 50.0), to = d))
|
||||
assertEquals(Point(100.0, 100.0), d.convert(Point(0.0, 0.0), to = c))
|
||||
assertEquals(Rect(100.0, 100.0, 50.0, 50.0), d.convert(Rect(0.0, 0.0, 50.0, 50.0), to = c))
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue