2019-08-13 23:54:29 +02:00
using System ;
2020-09-18 18:11:46 +02:00
using System.Linq ;
2019-08-13 23:54:29 +02:00
using Microsoft.Xna.Framework ;
using MLEM.Ui.Style ;
namespace MLEM.Ui.Elements {
2020-05-22 17:02:24 +02:00
/// <summary>
/// A tooltip element for use inside of a <see cref="UiSystem"/>.
/// A tooltip is a <see cref="Panel"/> with a custom cursor that always follows the position of the mouse.
/// Tooltips can easily be configured to be hooked onto an element, causing them to appear when it is moused, and disappear when it is not moused anymore.
/// </summary>
2019-12-31 14:08:13 +01:00
public class Tooltip : Panel {
2019-08-13 23:54:29 +02:00
2020-05-22 17:02:24 +02:00
/// <summary>
/// The offset that this tooltip's top left corner should have from the mouse position
/// </summary>
2019-12-31 14:08:13 +01:00
public StyleProp < Vector2 > MouseOffset ;
2020-05-22 17:02:24 +02:00
/// <summary>
/// The paragraph of text that this tooltip displays
/// </summary>
2019-12-28 14:23:40 +01:00
public Paragraph Paragraph ;
2019-08-13 23:54:29 +02:00
2020-05-22 17:02:24 +02:00
/// <summary>
/// Creates a new tooltip with the given settings
/// </summary>
/// <param name="width">The width of the tooltip</param>
/// <param name="text">The text to display on the tooltip</param>
/// <param name="elementToHover">The element that should automatically cause the tooltip to appear and disappear when hovered and not hovered, respectively</param>
2019-12-28 14:23:40 +01:00
public Tooltip ( float width , string text = null , Element elementToHover = null ) :
2019-12-31 14:08:13 +01:00
base ( Anchor . TopLeft , Vector2 . One , Vector2 . Zero ) {
2019-12-28 14:23:40 +01:00
if ( text ! = null ) {
this . Paragraph = this . AddChild ( new Paragraph ( Anchor . TopLeft , width , text ) ) ;
this . Paragraph . AutoAdjustWidth = true ;
}
2019-12-31 14:08:13 +01:00
this . SetWidthBasedOnChildren = true ;
this . SetHeightBasedOnChildren = true ;
this . ChildPadding = new Vector2 ( 2 ) ;
2019-12-28 14:23:40 +01:00
this . CanBeMoused = false ;
2019-08-24 20:45:40 +02:00
if ( elementToHover ! = null ) {
2019-12-28 14:23:40 +01:00
elementToHover . OnMouseEnter + = element = > {
2020-09-18 18:11:46 +02:00
// only display the tooltip if there is anything in it
2020-09-18 18:19:05 +02:00
if ( this . Children . All ( c = > c . IsHidden ) )
2020-09-18 18:11:46 +02:00
return ;
2020-02-06 01:51:41 +01:00
element . System . Add ( element . GetType ( ) . Name + "Tooltip" , this ) ;
2019-12-28 14:23:40 +01:00
this . SnapPositionToMouse ( ) ;
} ;
2019-09-15 02:21:42 +02:00
elementToHover . OnMouseExit + = element = > {
2020-02-06 01:51:41 +01:00
if ( this . System ! = null )
this . System . Remove ( this . Root . Name ) ;
2019-09-15 02:21:42 +02:00
} ;
2019-08-24 20:45:40 +02:00
}
2019-08-13 23:54:29 +02:00
}
2020-05-22 17:02:24 +02:00
/// <inheritdoc />
2019-08-13 23:54:29 +02:00
public override void Update ( GameTime time ) {
base . Update ( time ) ;
2019-12-28 14:23:40 +01:00
this . SnapPositionToMouse ( ) ;
}
2019-08-15 14:59:15 +02:00
2020-05-22 17:02:24 +02:00
/// <inheritdoc />
2019-12-28 14:23:40 +01:00
public override void ForceUpdateArea ( ) {
if ( this . Parent ! = null )
throw new NotSupportedException ( $"A tooltip shouldn't be the child of another element ({this.Parent})" ) ;
base . ForceUpdateArea ( ) ;
}
2020-05-22 17:02:24 +02:00
/// <inheritdoc />
2019-12-28 14:23:40 +01:00
protected override void InitStyle ( UiStyle style ) {
base . InitStyle ( style ) ;
2019-12-31 14:08:13 +01:00
this . Texture . SetFromStyle ( style . TooltipBackground ) ;
this . MouseOffset . SetFromStyle ( style . TooltipOffset ) ;
2020-10-31 17:55:46 +01:00
// we can't set from style here since it's a different element
this . Paragraph ? . TextColor . Set ( style . TooltipTextColor ) ;
2019-12-28 14:23:40 +01:00
}
2020-05-22 17:02:24 +02:00
/// <summary>
/// Causes this tooltip's position to be snapped to the mouse position.
/// </summary>
2019-12-28 14:23:40 +01:00
public void SnapPositionToMouse ( ) {
2020-02-06 01:51:41 +01:00
var viewport = this . System . Viewport . Size ;
2019-08-30 18:15:50 +02:00
var offset = this . Input . MousePosition . ToVector2 ( ) / this . Scale + this . MouseOffset ;
2019-08-15 14:59:15 +02:00
if ( offset . X < 0 )
offset . X = 0 ;
if ( offset . Y < 0 )
offset . Y = 0 ;
if ( offset . X * this . Scale + this . Area . Width > = viewport . X )
offset . X = ( viewport . X - this . Area . Width ) / this . Scale ;
if ( offset . Y * this . Scale + this . Area . Height > = viewport . Y )
offset . Y = ( viewport . Y - this . Area . Height ) / this . Scale ;
this . PositionOffset = offset ;
2019-08-13 23:54:29 +02:00
}
2019-12-29 15:18:49 +01:00
2019-08-13 23:54:29 +02:00
}
}