diff --git a/CHANGELOG.md b/CHANGELOG.md index c36459b..7c71bcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ Jump to version: ## 6.3.2 (In Development) +### MLEM.Ui +Additions +- Added the ability to set the anchor that should be used when a tooltip attaches to an element or the mouse +- Added the ability to display tooltips using the auto-nav style even when using the mouse + ## 6.3.1 No code changes diff --git a/Demos/GameImpl.cs b/Demos/GameImpl.cs index 6b43baa..45e0adf 100644 --- a/Demos/GameImpl.cs +++ b/Demos/GameImpl.cs @@ -77,7 +77,8 @@ namespace Demos { this.activeDemo = demo.Value.Item2.Invoke(this); this.activeDemo.LoadContent(); }, - PositionOffset = new Vector2(0, 1) + PositionOffset = new Vector2(0, 1), + Tooltip = {DisplayInAutoNavMode = true} }); } diff --git a/MLEM.Ui/Elements/Tooltip.cs b/MLEM.Ui/Elements/Tooltip.cs index 48ad306..9b16753 100644 --- a/MLEM.Ui/Elements/Tooltip.cs +++ b/MLEM.Ui/Elements/Tooltip.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; +using System.Drawing; using Microsoft.Xna.Framework; using MLEM.Input; using MLEM.Ui.Style; +using Color = Microsoft.Xna.Framework.Color; +using RectangleF = MLEM.Misc.RectangleF; #if FNA using MLEM.Extensions; #endif @@ -23,14 +26,26 @@ namespace MLEM.Ui.Elements { public readonly List Paragraphs = new List(); /// - /// The offset that this tooltip's top left corner should have from the mouse position + /// The offset that this tooltip should have from the mouse position /// public StyleProp MouseOffset; /// - /// The offset that this tooltip's top center coordinate should have from the bottom center of the element snapped to when is true. + /// The offset that this tooltip should have from the element snapped to when is true. /// public StyleProp AutoNavOffset; /// + /// The anchor that should be used when this tooltip is displayed using the mouse. The will be applied. + /// + public StyleProp MouseAnchor; + /// + /// The anchor that should be used when this tooltip is displayed using auto-nav mode. The will be applied. + /// + public StyleProp AutoNavAnchor; + /// + /// If this is , and the mouse is used, the tooltip will attach to the hovered element in a static position using the and properties, rather than following the mouse cursor exactly. + /// + public StyleProp UseAutoNavBehaviorForMouse; + /// /// The amount of time that the mouse has to be over an element before it appears /// public StyleProp Delay; @@ -79,6 +94,7 @@ namespace MLEM.Ui.Elements { /// The position that this tooltip should be following (or snapped to) instead of the . /// If this value is unset, will be used as the snap position. /// Note that is still applied with this value set. + /// Note that, if is , this value is ignored. /// public virtual Vector2? SnapPosition { get; set; } @@ -151,6 +167,9 @@ namespace MLEM.Ui.Elements { this.Texture = this.Texture.OrStyle(style.TooltipBackground); this.MouseOffset = this.MouseOffset.OrStyle(style.TooltipOffset); this.AutoNavOffset = this.AutoNavOffset.OrStyle(style.TooltipAutoNavOffset); + this.MouseAnchor = this.MouseAnchor.OrStyle(style.TooltipMouseAnchor); + this.AutoNavAnchor = this.AutoNavAnchor.OrStyle(style.TooltipAutoNavAnchor); + this.UseAutoNavBehaviorForMouse = this.UseAutoNavBehaviorForMouse.OrStyle(style.TooltipUseAutoNavBehaviorForMouse); this.Delay = this.Delay.OrStyle(style.TooltipDelay); this.ParagraphTextColor = this.ParagraphTextColor.OrStyle(style.TooltipTextColor); this.ParagraphTextScale = this.ParagraphTextScale.OrStyle(style.TextScale); @@ -201,11 +220,10 @@ namespace MLEM.Ui.Elements { public void SnapPositionToMouse() { Vector2 snapPosition; if (this.snapElement != null) { - // center our snap position below the snap element - snapPosition = new Vector2(this.snapElement.DisplayArea.Center.X, this.snapElement.DisplayArea.Bottom) + this.AutoNavOffset; - snapPosition.X -= this.DisplayArea.Width / 2F; + snapPosition = this.GetSnapOffset(this.AutoNavAnchor, this.snapElement.DisplayArea, this.AutoNavOffset); } else { - snapPosition = (this.SnapPosition ?? this.Input.ViewportMousePosition.ToVector2()) + this.MouseOffset.Value; + var mouseBounds = new RectangleF(this.SnapPosition ?? this.Input.ViewportMousePosition.ToVector2(), Vector2.Zero); + snapPosition = this.GetSnapOffset(this.MouseAnchor, mouseBounds, this.MouseOffset); } var viewport = this.System.Viewport; @@ -255,8 +273,19 @@ namespace MLEM.Ui.Elements { /// /// The element that should automatically cause the tooltip to appear and disappear when hovered and not hovered, respectively public void AddToElement(Element elementToHover) { - elementToHover.OnMouseEnter += e => this.Display(e.System, $"{e.GetType().Name}Tooltip"); - elementToHover.OnMouseExit += e => this.Remove(); + // mouse controls + elementToHover.OnMouseEnter += e => { + if (this.UseAutoNavBehaviorForMouse) + this.snapElement = e; + this.Display(e.System, $"{e.GetType().Name}Tooltip"); + }; + elementToHover.OnMouseExit += e => { + this.Remove(); + if (this.UseAutoNavBehaviorForMouse) + this.snapElement = null; + }; + + // auto-nav controls elementToHover.OnSelected += e => { if (this.DisplayInAutoNavMode && e.Controls.IsAutoNavMode) { this.snapElement = e; @@ -312,5 +341,30 @@ namespace MLEM.Ui.Elements { paragraph.AutoAdjustWidth = true; } + private Vector2 GetSnapOffset(Anchor anchor, RectangleF snapBounds, Vector2 offset) { + switch (anchor) { + case Anchor.TopLeft: + return snapBounds.Location - this.DisplayArea.Size - offset; + case Anchor.TopCenter: + return new Vector2(snapBounds.Center.X - this.DisplayArea.Width / 2F, snapBounds.Top - this.DisplayArea.Height) - offset; + case Anchor.TopRight: + return new Vector2(snapBounds.Right + offset.X, snapBounds.Top - this.DisplayArea.Height - offset.Y); + case Anchor.CenterLeft: + return new Vector2(snapBounds.X - this.DisplayArea.Width - offset.X, snapBounds.Center.Y - this.DisplayArea.Height / 2 + offset.Y); + case Anchor.Center: + return snapBounds.Center - this.DisplayArea.Size / 2 + offset; + case Anchor.CenterRight: + return new Vector2(snapBounds.Right, snapBounds.Center.Y - this.DisplayArea.Height / 2) + offset; + case Anchor.BottomLeft: + return new Vector2(snapBounds.X - this.DisplayArea.Width - offset.X, snapBounds.Bottom + offset.Y); + case Anchor.BottomCenter: + return new Vector2(snapBounds.Center.X - this.DisplayArea.Width / 2F, snapBounds.Bottom) + offset; + case Anchor.BottomRight: + return snapBounds.Location + snapBounds.Size + offset; + default: + throw new NotSupportedException($"Tooltip anchors don't support the {anchor} value"); + } + } + } } diff --git a/MLEM.Ui/Style/UiStyle.cs b/MLEM.Ui/Style/UiStyle.cs index 71c625a..9fad332 100644 --- a/MLEM.Ui/Style/UiStyle.cs +++ b/MLEM.Ui/Style/UiStyle.cs @@ -166,6 +166,9 @@ namespace MLEM.Ui.Style { /// The offset of the element's top center coordinate from the bottom center of the element snapped to when is true. /// public Vector2 TooltipAutoNavOffset = new Vector2(0, 8); + public Anchor TooltipAutoNavAnchor = Anchor.BottomCenter; + public Anchor TooltipMouseAnchor = Anchor.BottomRight; + public bool TooltipUseAutoNavBehaviorForMouse; /// /// The color that the text of a should have ///