From 5b99f2949004774005fc2c27c19453a107bd548e Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Mon, 22 Nov 2021 15:13:08 +0100 Subject: [PATCH] Fixed some inconsistencies with element transformations and mouse interaction --- CHANGELOG.md | 1 + MLEM.Ui/Elements/Element.cs | 25 +++++++++++++++++++++++-- MLEM.Ui/Elements/Panel.cs | 5 +++-- MLEM.Ui/Elements/Paragraph.cs | 2 +- MLEM.Ui/Elements/ScrollBar.cs | 9 ++++----- MLEM.Ui/UiControls.cs | 5 ++--- 6 files changed, 34 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c40423..9389be8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Fixes - Fixed VerticalSpace height parameter being an integer - Fixed text not being pasted into a text field at all if it contains characters that don't match the input rule - Fixed panels that don't auto-hide their scroll bars ignoring their width for child padding +- Fixed some inconsistencies with element transformations and mouse interaction Removals - *Removed ScrollBar ScrollerOffset* diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index 3115916..9e439bd 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -956,8 +956,7 @@ namespace MLEM.Ui.Elements { public virtual Element GetElementUnderPos(Vector2 position) { if (this.IsHidden) return null; - if (this.Transform != Matrix.Identity) - position = Vector2.Transform(position, Matrix.Invert(this.Transform)); + position = this.TransformInverse(position); var relevant = this.GetRelevantChildren(); for (var i = relevant.Count - 1; i >= 0; i--) { var element = relevant[i].GetElementUnderPos(position); @@ -1019,6 +1018,28 @@ namespace MLEM.Ui.Elements { this.SecondActionSound.SetFromStyle(style.ActionSound); } + /// + /// Transforms the given by the inverse of this element's matrix. + /// + /// The position to transform + /// The transformed position + protected Vector2 TransformInverse(Vector2 position) { + return this.Transform != Matrix.Identity ? Vector2.Transform(position, Matrix.Invert(this.Transform)) : position; + } + + /// + /// Transforms the given by this element's 's , the inverses of all of the matrices of this element's parent tree (), and the inverse of this element's matrix. + /// Note that, when using , this operation is done recursively, which is more efficient. + /// + /// The position to transform + /// The transformed position + protected Vector2 TransformInverseAll(Vector2 position) { + position = Vector2.Transform(position, this.Root.InvTransform); + foreach (var parent in this.GetParentTree().Reverse()) + position = parent.TransformInverse(position); + return this.TransformInverse(position); + } + /// /// A delegate used for the event. /// diff --git a/MLEM.Ui/Elements/Panel.cs b/MLEM.Ui/Elements/Panel.cs index 173a656..089cf60 100644 --- a/MLEM.Ui/Elements/Panel.cs +++ b/MLEM.Ui/Elements/Panel.cs @@ -189,8 +189,9 @@ namespace MLEM.Ui.Elements { /// public override Element GetElementUnderPos(Vector2 position) { // if overflow is handled, don't propagate mouse checks to hidden children - if (this.scrollOverflow && !this.GetRenderTargetArea().Contains(position)) - return !this.IsHidden && this.CanBeMoused && this.DisplayArea.Contains(position) ? this : null; + var transformed = this.TransformInverse(position); + if (this.scrollOverflow && !this.GetRenderTargetArea().Contains(transformed)) + return !this.IsHidden && this.CanBeMoused && this.DisplayArea.Contains(transformed) ? this : null; return base.GetElementUnderPos(position); } diff --git a/MLEM.Ui/Elements/Paragraph.cs b/MLEM.Ui/Elements/Paragraph.cs index adedcd0..a781446 100644 --- a/MLEM.Ui/Elements/Paragraph.cs +++ b/MLEM.Ui/Elements/Paragraph.cs @@ -251,7 +251,7 @@ namespace MLEM.Ui.Elements { return ret; // check if any of our token's parts are hovered foreach (var rect in this.Token.GetArea(this.Parent.DisplayArea.Location, this.Scale * this.textScale)) { - if (rect.Contains(position)) + if (rect.Contains(this.TransformInverse(position))) return this; } return null; diff --git a/MLEM.Ui/Elements/ScrollBar.cs b/MLEM.Ui/Elements/ScrollBar.cs index f97bec9..63d90d2 100644 --- a/MLEM.Ui/Elements/ScrollBar.cs +++ b/MLEM.Ui/Elements/ScrollBar.cs @@ -137,15 +137,14 @@ namespace MLEM.Ui.Elements { // MOUSE INPUT var moused = this.Controls.MousedElement; - var mousedPos = Vector2.Transform(this.Input.MousePosition.ToVector2(), this.Root.InvTransform); if (moused == this && this.Controls.Input.IsMouseButtonPressed(MouseButton.Left)) { this.isMouseHeld = true; - this.scrollStartOffset = mousedPos - this.ScrollerPosition; + this.scrollStartOffset = this.TransformInverseAll(this.Input.MousePosition.ToVector2()) - this.ScrollerPosition; } else if (this.isMouseHeld && !this.Controls.Input.IsMouseButtonDown(MouseButton.Left)) { this.isMouseHeld = false; } if (this.isMouseHeld) - this.ScrollToPos(mousedPos); + this.ScrollToPos(this.TransformInverseAll(this.Input.MousePosition.ToVector2())); if (!this.Horizontal && moused != null && (moused == this.Parent || moused.GetParentTree().Contains(this.Parent))) { var scroll = this.Input.LastScrollWheel - this.Input.ScrollWheel; if (scroll != 0) @@ -157,7 +156,7 @@ namespace MLEM.Ui.Elements { // are we dragging on top of the panel? if (this.Input.GetGesture(GestureType.VerticalDrag, out var drag)) { // if the element under the drag's start position is on top of the panel, start dragging - var touched = this.Parent.GetElementUnderPos(Vector2.Transform(drag.Position, this.Root.InvTransform)); + var touched = this.Parent.GetElementUnderPos(this.TransformInverseAll(drag.Position)); if (touched != null && touched != this) this.isDragging = true; @@ -173,7 +172,7 @@ namespace MLEM.Ui.Elements { this.isTouchHeld = false; } else { foreach (var loc in this.Input.TouchState) { - var pos = Vector2.Transform(loc.Position, this.Root.InvTransform); + var pos = this.TransformInverseAll(loc.Position); // if we just started touching and are on top of the scroller, then we should start scrolling if (this.DisplayArea.Contains(pos) && !loc.TryGetPreviousLocation(out _)) { this.isTouchHeld = true; diff --git a/MLEM.Ui/UiControls.cs b/MLEM.Ui/UiControls.cs index f8f5ebb..e376503 100644 --- a/MLEM.Ui/UiControls.cs +++ b/MLEM.Ui/UiControls.cs @@ -237,11 +237,10 @@ namespace MLEM.Ui { /// Throughout the ui system, this is used for mouse input querying. /// /// The position to query - /// If this value is true, the will be applied. /// The element under the position, or null if there isn't one - public virtual Element GetElementUnderPos(Vector2 position, bool transform = true) { + public virtual Element GetElementUnderPos(Vector2 position) { foreach (var root in this.System.GetRootElements()) { - var pos = transform ? Vector2.Transform(position, root.InvTransform) : position; + var pos = Vector2.Transform(position, root.InvTransform); var moused = root.Element.GetElementUnderPos(pos); if (moused != null) return moused;