Add Z index and view sorting

This commit is contained in:
Shadowfacts 2019-06-25 18:39:58 -04:00
parent 27bad18931
commit b2499ad247
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
2 changed files with 45 additions and 7 deletions

View File

@ -26,6 +26,8 @@ class Window {
*/ */
val views: List<View> = _views val views: List<View> = _views
private var viewsSortedByZIndex: List<View> = listOf()
/** /**
* Adds the given view as a top-level view in this window. * Adds the given view as a top-level view in this window.
* *
@ -34,6 +36,9 @@ class Window {
*/ */
fun <T: View> addView(view: T): T { fun <T: View> addView(view: T): T {
_views.add(view) _views.add(view)
viewsSortedByZIndex = views.sortedBy(View::zIndex)
view.window = this
view.solver = solver view.solver = solver
view.wasAdded() view.wasAdded()
@ -42,11 +47,22 @@ class Window {
} }
/** /**
* Attempts to find a top level view of this window that contains the given point. * Finds all views in this window at the given point.
* If there are multiple overlapping views, which one this method returns is undefined.
* *
* @param point The point to find views at, in the coordinate system of the window. * @param point The point to find views at, in the coordinate system of the window.
* @return The view, if any, that contains the given point. * @return All views that contain the point.
*/
fun viewsAtPoint(point: Point): List<View> {
return views.filter { point in it.frame }
}
/**
* Attempts to find a top level view of this window that contains the given point.
* If there are multiple overlapping views, which one this method returns is undefined.
* [viewsAtPoint] may be used, and the resulting List sorted by [View.zIndex].
*
* @param point The point to find views at, in the coordinate system of the window.
* @return the Veiw, if any, that contain the given point.
*/ */
fun viewAtPoint(point: Point): View? { fun viewAtPoint(point: Point): View? {
return views.firstOrNull { point in it.frame } return views.firstOrNull { point in it.frame }
@ -69,7 +85,7 @@ class Window {
* @param delta The time elapsed since the last frame. * @param delta The time elapsed since the last frame.
*/ */
fun draw(mouse: Point, delta: Float) { fun draw(mouse: Point, delta: Float) {
views.forEach { viewsSortedByZIndex.forEach {
val mouseInView = Point(mouse.x - it.frame.left, mouse.y - it.frame.top) val mouseInView = Point(mouse.x - it.frame.left, mouse.y - it.frame.top)
it.draw(mouseInView, delta) it.draw(mouseInView, delta)
} }
@ -84,7 +100,7 @@ class Window {
* @return Whether the mouse click was handled by a view. * @return Whether the mouse click was handled by a view.
*/ */
fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean { fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
val view = viewAtPoint(point) val view = viewsAtPoint(point).minBy(View::zIndex)
if (view != null) { if (view != null) {
val pointInView = Point(point.x - view.frame.left, point.y - view.frame.top) val pointInView = Point(point.x - view.frame.left, point.y - view.frame.top)
return view.mouseClicked(pointInView, mouseButton) return view.mouseClicked(pointInView, mouseButton)

View File

@ -78,6 +78,12 @@ open class View() {
*/ */
lateinit var bounds: Rect lateinit var bounds: Rect
/**
* The position on the Z-axis of this view.
* Views are rendered from lowest Z index to highest. Clicks are handled from highest to lowest.
*/
var zIndex: Double = 0.0
/** /**
* The intrinsic size of this view's content. May be null if the view doesn't have any content or there is no * The intrinsic size of this view's content. May be null if the view doesn't have any content or there is no
* intrinsic size. * intrinsic size.
@ -104,6 +110,9 @@ open class View() {
var superview: View? = null var superview: View? = null
// _subviews is the internal, mutable object since we only want it to by mutated by the add/removeSubview methods // _subviews is the internal, mutable object since we only want it to by mutated by the add/removeSubview methods
private val _subviews = LinkedList<View>() private val _subviews = LinkedList<View>()
private var subviewsSortedByZIndex: List<View> = listOf()
/** /**
* The list of all the subviews of this view. * The list of all the subviews of this view.
* This list should never by mutated directly, only by the [addSubview]/[removeSubview] methods. * This list should never by mutated directly, only by the [addSubview]/[removeSubview] methods.
@ -143,6 +152,8 @@ open class View() {
*/ */
fun <T: View> addSubview(view: T): T { fun <T: View> addSubview(view: T): T {
_subviews.add(view) _subviews.add(view)
subviewsSortedByZIndex = subviews.sortedBy(View::zIndex)
view.superview = this view.superview = this
view.solver = solver view.solver = solver
@ -151,9 +162,20 @@ open class View() {
return view return view
} }
/**
* Finds all subviews that contain the given point.
*
* @param point The point to find subviews for, in the coordinate system of this view.
* @return All views that contain the given point.
*/
fun subviewsAtPoint(point: Point): List<View> {
return subviews.filter { point in it.frame }
}
/** /**
* Attempts to find a subview which contains the given point. * Attempts to find a subview which contains the given point.
* If multiple subviews contain the given point, which one this method returns is undefined. * If multiple subviews contain the given point, which one this method returns is undefined.
* [subviewsAtPoint] may be used, and the resulting List sorted by [View.zIndex].
* *
* @param point The point to find a subview for, in the coordinate system of this view. * @param point The point to find a subview for, in the coordinate system of this view.
* @return The view, if any, that contains the given point. * @return The view, if any, that contains the given point.
@ -233,7 +255,7 @@ open class View() {
drawContent(mouse, delta) drawContent(mouse, delta)
subviews.forEach { subviewsSortedByZIndex.forEach {
val mouseInView = convert(mouse, to = it) val mouseInView = convert(mouse, to = it)
it.draw(mouseInView, delta) it.draw(mouseInView, delta)
} }
@ -261,7 +283,7 @@ open class View() {
* @return Whether the mouse click was handled by this view or any subviews. * @return Whether the mouse click was handled by this view or any subviews.
*/ */
open fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean { open fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
val view = subviewAtPoint(point) val view = subviewsAtPoint(point).maxBy(View::zIndex)
if (view != null) { if (view != null) {
val pointInView = convert(point, to = view) val pointInView = convert(point, to = view)
return view.mouseClicked(pointInView, mouseButton) return view.mouseClicked(pointInView, mouseButton)