Merged in lucasvinbr/unity-ui-extensions (pull request #38)

Mixed BoundTooltip with ToolTip, added Screenspace Overlay support

Approved-by: Simon Jackson <darkside@xna-uk.net>
pull/413/head
Lucas Ferres 2018-11-26 12:26:43 +00:00 committed by Simon Jackson
commit 693a49997b
5 changed files with 346 additions and 78 deletions

View File

@ -3,7 +3,7 @@
namespace UnityEngine.UI.Extensions
{
[AddComponentMenu("UI/Extensions/Bound Tooltip/Tooltip Item")]
[AddComponentMenu("UI/Extensions/Bound Tooltip/Bound Tooltip Item")]
public class BoundTooltipItem : MonoBehaviour
{
public bool IsActive

View File

@ -4,7 +4,7 @@ using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[AddComponentMenu("UI/Extensions/Bound Tooltip/Tooltip Trigger")]
[AddComponentMenu("UI/Extensions/Bound Tooltip/Bound Tooltip Trigger")]
public class BoundTooltipTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, ISelectHandler, IDeselectHandler
{
[TextAreaAttribute]

View File

@ -1,7 +1,8 @@
/// Credit drHogan
/// Sourced from - http://forum.unity3d.com/threads/screenspace-camera-tooltip-controller-sweat-and-tears.293991/#post-1938929
/// updated ddreaper - refactored code to be more performant.
/// *Note - only works for Screenspace Camera canvases at present, needs updating to include Screenspace and Worldspace!
/// updated lucasvinbr - mixed with BoundTooltip, should work with Screenspace Camera (non-rotated) and Overlay
/// *Note - only works for non-rotated Screenspace Camera and Screenspace Overlay canvases at present, needs updating to include rotated Screenspace Camera and Worldspace!
//ToolTip is written by Emiliano Pastorelli, H&R Tallinn (Estonia), http://www.hammerandravens.com
//Copyright (c) 2015 Emiliano Pastorelli, H&R - Hammer&Ravens, Tallinn, Estonia.
@ -22,144 +23,292 @@
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/Tooltip")]
[AddComponentMenu("UI/Extensions/Tooltip/Tooltip")]
public class ToolTip : MonoBehaviour
{
//text of the tooltip
private Text _text;
private RectTransform _rectTransform;
private RectTransform _rectTransform, canvasRectTransform;
[Tooltip("The canvas used by the tooltip as positioning and scaling reference. Should usually be the root Canvas of the hierarchy this component is in")]
public Canvas canvas;
[Tooltip("Sets if tooltip triggers will run ForceUpdateCanvases and refresh the tooltip's layout group " +
"(if any) when hovered, in order to prevent momentaneous misplacement sometimes caused by ContentSizeFitters")]
public bool tooltipTriggersCanForceCanvasUpdate = false;
/// <summary>
/// the tooltip's Layout Group, if any
/// </summary>
private LayoutGroup _layoutGroup;
//if the tooltip is inside a UI element
private bool _inside;
// private bool _xShifted, _yShifted = false;
private float width, height;//, canvasWidth, canvasHeight;
// private int screenWidth, screenHeight;
public float YShift,xShift;
private float YShift,xShift;
private RenderMode _guiMode;
[HideInInspector]
public RenderMode guiMode;
private Camera _guiCamera;
public Camera GuiCamera
{
get
{
if (!_guiCamera) {
_guiCamera = Camera.main;
}
return _guiCamera;
}
}
private Vector3 screenLowerLeft, screenUpperRight, shiftingVector;
/// <summary>
/// a screen-space point where the tooltip would be placed before applying X and Y shifts and border checks
/// </summary>
private Vector3 baseTooltipPos;
private Vector3 newTTPos;
private Vector3 adjustedNewTTPos;
private Vector3 adjustedTTLocalPos;
private Vector3 shifterForBorders;
private float borderTest;
// Standard Singleton Access
private static ToolTip instance;
public static ToolTip Instance
{
get
{
if (instance == null)
instance = FindObjectOfType<ToolTip>();
return instance;
}
}
void Reset() {
canvas = GetComponentInParent<Canvas>();
canvas = canvas.rootCanvas;
}
// Use this for initialization
public void Awake()
{
var _canvas = GetComponentInParent<Canvas>();
_guiCamera = _canvas.worldCamera;
_guiMode = _canvas.renderMode;
instance = this;
if (!canvas) {
canvas = GetComponentInParent<Canvas>();
canvas = canvas.rootCanvas;
}
_guiCamera = canvas.worldCamera;
guiMode = canvas.renderMode;
_rectTransform = GetComponent<RectTransform>();
canvasRectTransform = canvas.GetComponent<RectTransform>();
_layoutGroup = GetComponentInChildren<LayoutGroup>();
_text = GetComponentInChildren<Text>();
_inside = false;
//size of the screen
// screenWidth = Screen.width;
// screenHeight = Screen.height;
xShift = 0f;
YShift = -30f;
// _xShifted = _yShifted = false;
this.gameObject.SetActive(false);
}
//Call this function externally to set the text of the template and activate the tooltip
public void SetTooltip(string ttext)
public void SetTooltip(string ttext, Vector3 basePos, bool refreshCanvasesBeforeGetSize = false)
{
if (_guiMode == RenderMode.ScreenSpaceCamera)
{
//set the text and fit the tooltip panel to the text size
baseTooltipPos = basePos;
//set the text
if (_text) {
_text.text = ttext;
_rectTransform.sizeDelta = new Vector2(_text.preferredWidth + 40f, _text.preferredHeight + 25f);
OnScreenSpaceCamera();
}
else {
Debug.LogWarning("[ToolTip] Couldn't set tooltip text, tooltip has no child Text component");
}
ContextualTooltipUpdate(refreshCanvasesBeforeGetSize);
}
//call this function on mouse exit to deactivate the template
public void HideTooltip()
{
if (_guiMode == RenderMode.ScreenSpaceCamera)
{
this.gameObject.SetActive(false);
_inside = false;
}
gameObject.SetActive(false);
_inside = false;
}
// Update is called once per frame
void FixedUpdate()
void Update()
{
if (_inside)
{
if (_guiMode == RenderMode.ScreenSpaceCamera)
{
OnScreenSpaceCamera();
}
ContextualTooltipUpdate();
}
}
//main tooltip edge of screen guard and movement
public void OnScreenSpaceCamera()
/// <summary>
/// forces rebuilding of Canvases in order to update the tooltip's content size fitting.
/// Can prevent the tooltip from being visibly misplaced for one frame when being resized.
/// Only runs if tooltipTriggersCanForceCanvasUpdate is true
/// </summary>
public void RefreshTooltipSize() {
if (tooltipTriggersCanForceCanvasUpdate) {
Canvas.ForceUpdateCanvases();
if (_layoutGroup) {
_layoutGroup.enabled = false;
_layoutGroup.enabled = true;
}
}
}
/// <summary>
/// Runs the appropriate tooltip placement method, according to the parent canvas's render mode
/// </summary>
/// <param name="refreshCanvasesBeforeGettingSize"></param>
public void ContextualTooltipUpdate(bool refreshCanvasesBeforeGettingSize = false) {
switch (guiMode) {
case RenderMode.ScreenSpaceCamera:
OnScreenSpaceCamera(refreshCanvasesBeforeGettingSize);
break;
case RenderMode.ScreenSpaceOverlay:
OnScreenSpaceOverlay(refreshCanvasesBeforeGettingSize);
break;
}
}
//main tooltip edge of screen guard and movement - camera
public void OnScreenSpaceCamera(bool refreshCanvasesBeforeGettingSize = false)
{
Vector3 newPos = _guiCamera.ScreenToViewportPoint(Input.mousePosition - new Vector3(xShift, YShift, 0f));
Vector3 newPosWVP = _guiCamera.ViewportToWorldPoint(newPos);
shiftingVector.x = xShift;
shiftingVector.y = YShift;
baseTooltipPos.z = canvas.planeDistance;
newTTPos = GuiCamera.ScreenToViewportPoint(baseTooltipPos - shiftingVector);
adjustedNewTTPos = GuiCamera.ViewportToWorldPoint(newTTPos);
gameObject.SetActive(true);
if (refreshCanvasesBeforeGettingSize) RefreshTooltipSize();
//consider scaled dimensions when comparing against the edges
width = transform.lossyScale.x * _rectTransform.sizeDelta[0];
height = transform.lossyScale.y * _rectTransform.sizeDelta[1];
// check and solve problems for the tooltip that goes out of the screen on the horizontal axis
RectTransformUtility.ScreenPointToWorldPointInRectangle(canvasRectTransform, Vector2.zero, GuiCamera, out screenLowerLeft);
RectTransformUtility.ScreenPointToWorldPointInRectangle(canvasRectTransform, new Vector2(Screen.width, Screen.height), GuiCamera, out screenUpperRight);
//check for right edge of screen
borderTest = (adjustedNewTTPos.x + width / 2);
if (borderTest > screenUpperRight.x)
{
shifterForBorders.x = borderTest - screenUpperRight.x;
adjustedNewTTPos.x -= shifterForBorders.x;
}
//check for left edge of screen
borderTest = (adjustedNewTTPos.x - width / 2);
if (borderTest < screenLowerLeft.x)
{
shifterForBorders.x = screenLowerLeft.x - borderTest;
adjustedNewTTPos.x += shifterForBorders.x;
}
// check and solve problems for the tooltip that goes out of the screen on the vertical axis
//check for lower edge of the screen
borderTest = (adjustedNewTTPos.y - height / 2);
if (borderTest < screenLowerLeft.y) {
shifterForBorders.y = screenLowerLeft.y - borderTest;
adjustedNewTTPos.y += shifterForBorders.y;
}
//check for upper edge of the screen
borderTest = (adjustedNewTTPos.y + height / 2);
if (borderTest > screenUpperRight.y)
{
shifterForBorders.y = borderTest - screenUpperRight.y;
adjustedNewTTPos.y -= shifterForBorders.y;
}
//failed attempt to circumvent issues caused when rotating the camera
adjustedNewTTPos = transform.rotation * adjustedNewTTPos;
transform.position = adjustedNewTTPos;
adjustedTTLocalPos = transform.localPosition;
adjustedTTLocalPos.z = 0;
transform.localPosition = adjustedTTLocalPos;
_inside = true;
}
//main tooltip edge of screen guard and movement - overlay
public void OnScreenSpaceOverlay(bool refreshCanvasesBeforeGettingSize = false) {
shiftingVector.x = xShift;
shiftingVector.y = YShift;
newTTPos = (baseTooltipPos - shiftingVector) / canvas.scaleFactor;
adjustedNewTTPos = newTTPos;
gameObject.SetActive(true);
if (refreshCanvasesBeforeGettingSize) RefreshTooltipSize();
width = _rectTransform.sizeDelta[0];
height = _rectTransform.sizeDelta[1];
// check and solve problems for the tooltip that goes out of the screen on the horizontal axis
float val;
Vector3 lowerLeft = _guiCamera.ViewportToWorldPoint(new Vector3(0.0f, 0.0f, 0.0f));
Vector3 upperRight = _guiCamera.ViewportToWorldPoint(new Vector3(1.0f, 1.0f, 0.0f));
//screen's 0 = overlay canvas's 0 (always?)
screenLowerLeft = Vector3.zero;
screenUpperRight = canvasRectTransform.sizeDelta;
//check for right edge of screen
val = (newPosWVP.x + width / 2);
if (val > upperRight.x)
{
Vector3 shifter = new Vector3(val - upperRight.x, 0f, 0f);
Vector3 newWorldPos = new Vector3(newPosWVP.x - shifter.x, newPos.y, 0f);
newPos.x = _guiCamera.WorldToViewportPoint(newWorldPos).x;
borderTest = (newTTPos.x + width / 2);
if (borderTest > screenUpperRight.x) {
shifterForBorders.x = borderTest - screenUpperRight.x;
adjustedNewTTPos.x -= shifterForBorders.x;
}
//check for left edge of screen
val = (newPosWVP.x - width / 2);
if (val < lowerLeft.x)
{
Vector3 shifter = new Vector3(lowerLeft.x - val, 0f, 0f);
Vector3 newWorldPos = new Vector3(newPosWVP.x + shifter.x, newPos.y, 0f);
newPos.x = _guiCamera.WorldToViewportPoint(newWorldPos).x;
borderTest = (adjustedNewTTPos.x - width / 2);
if (borderTest < screenLowerLeft.x) {
shifterForBorders.x = screenLowerLeft.x - borderTest;
adjustedNewTTPos.x += shifterForBorders.x;
}
// check and solve problems for the tooltip that goes out of the screen on the vertical axis
//check for lower edge of the screen
borderTest = (adjustedNewTTPos.y - height / 2);
if (borderTest < screenLowerLeft.y) {
shifterForBorders.y = screenLowerLeft.y - borderTest;
adjustedNewTTPos.y += shifterForBorders.y;
}
//check for upper edge of the screen
val = (newPosWVP.y + height / 2);
if (val > upperRight.y)
{
Vector3 shifter = new Vector3(0f, 35f + height / 2, 0f);
Vector3 newWorldPos = new Vector3(newPos.x, newPosWVP.y - shifter.y, 0f);
newPos.y = _guiCamera.WorldToViewportPoint(newWorldPos).y;
borderTest = (adjustedNewTTPos.y + height / 2);
if (borderTest > screenUpperRight.y) {
shifterForBorders.y = borderTest - screenUpperRight.y;
adjustedNewTTPos.y -= shifterForBorders.y;
}
//check for lower edge of the screen (if the shifts of the tooltip are kept as in this code, no need for this as the tooltip always appears above the mouse bu default)
val = (newPosWVP.y - height / 2);
if (val < lowerLeft.y)
{
Vector3 shifter = new Vector3(0f, 35f + height / 2, 0f);
Vector3 newWorldPos = new Vector3(newPos.x, newPosWVP.y + shifter.y, 0f);
newPos.y = _guiCamera.WorldToViewportPoint(newWorldPos).y;
}
//remove scale factor for the actual positioning of the TT
adjustedNewTTPos *= canvas.scaleFactor;
transform.position = adjustedNewTTPos;
this.transform.position = new Vector3(newPosWVP.x, newPosWVP.y, 0f);
this.gameObject.SetActive(true);
_inside = true;
}
}

View File

@ -0,0 +1,108 @@
using System.Collections;
///Credit Martin Nerurkar // www.martin.nerurkar.de // www.sharkbombs.com
///Sourced from - http://www.sharkbombs.com/2015/02/10/tooltips-with-the-new-unity-ui-ugui/
using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/Tooltip/Tooltip Trigger")]
public class TooltipTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, ISelectHandler, IDeselectHandler
{
[TextAreaAttribute]
public string text;
public enum TooltipPositioningType {
mousePosition,
mousePositionAndFollow,
transformPosition
}
[Tooltip("Defines where the tooltip will be placed and how that placement will occur. Transform position will always be used if this element wasn't selected via mouse")]
public TooltipPositioningType tooltipPositioningType = TooltipPositioningType.mousePosition;
/// <summary>
/// This info is needed to make sure we make the necessary translations if the tooltip and this trigger are children of different space canvases
/// </summary>
private bool isChildOfOverlayCanvas = false;
private bool hovered = false;
public Vector3 offset;
void Start() {
//attempt to check if our canvas is overlay or not and check our "is overlay" accordingly
Canvas ourCanvas = GetComponentInParent<Canvas>();
if (ourCanvas && ourCanvas.renderMode == RenderMode.ScreenSpaceOverlay) {
isChildOfOverlayCanvas = true;
}
}
/// <summary>
/// Checks if the tooltip and the transform this trigger is attached to are children of differently-spaced Canvases
/// </summary>
public bool WorldToScreenIsRequired
{
get
{
return (isChildOfOverlayCanvas && ToolTip.Instance.guiMode == RenderMode.ScreenSpaceCamera) ||
(!isChildOfOverlayCanvas && ToolTip.Instance.guiMode == RenderMode.ScreenSpaceOverlay);
}
}
public void OnPointerEnter(PointerEventData eventData)
{
switch (tooltipPositioningType) {
case TooltipPositioningType.mousePosition:
StartHover(Input.mousePosition + offset, true);
break;
case TooltipPositioningType.mousePositionAndFollow:
StartHover(Input.mousePosition + offset, true);
hovered = true;
StartCoroutine(HoveredMouseFollowingLoop());
break;
case TooltipPositioningType.transformPosition:
StartHover((WorldToScreenIsRequired ?
ToolTip.Instance.GuiCamera.WorldToScreenPoint(transform.position) :
transform.position) + offset, true);
break;
}
}
IEnumerator HoveredMouseFollowingLoop() {
while (hovered) {
StartHover(Input.mousePosition + offset);
yield return null;
}
}
public void OnSelect(BaseEventData eventData)
{
StartHover((WorldToScreenIsRequired ?
ToolTip.Instance.GuiCamera.WorldToScreenPoint(transform.position) :
transform.position) + offset, true);
}
public void OnPointerExit(PointerEventData eventData)
{
StopHover();
}
public void OnDeselect(BaseEventData eventData)
{
StopHover();
}
void StartHover(Vector3 position, bool shouldCanvasUpdate = false)
{
ToolTip.Instance.SetTooltip(text, position, shouldCanvasUpdate);
}
void StopHover()
{
hovered = false;
ToolTip.Instance.HideTooltip();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: abe02588cca16964c8571b21eefea5d6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: