Mixed BoundTooltip with ToolTip, added Screenspace Overlay support

pull/413/head
Lucas Vinicius 2018-11-25 22:56:54 -02:00
parent 37aec29aa0
commit 6c639c7f51
5 changed files with 355 additions and 87 deletions

View File

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

View File

@ -4,7 +4,7 @@ using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions 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 public class BoundTooltipTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, ISelectHandler, IDeselectHandler
{ {
[TextAreaAttribute] [TextAreaAttribute]

View File

@ -1,7 +1,8 @@
/// Credit drHogan /// Credit drHogan
/// Sourced from - http://forum.unity3d.com/threads/screenspace-camera-tooltip-controller-sweat-and-tears.293991/#post-1938929 /// 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. /// 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 //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. //Copyright (c) 2015 Emiliano Pastorelli, H&R - Hammer&Ravens, Tallinn, Estonia.
@ -22,145 +23,293 @@
namespace UnityEngine.UI.Extensions namespace UnityEngine.UI.Extensions
{ {
[RequireComponent(typeof(RectTransform))] [RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/Tooltip")] [AddComponentMenu("UI/Extensions/Tooltip/Tooltip")]
public class ToolTip : MonoBehaviour public class ToolTip : MonoBehaviour
{ {
//text of the tooltip //text of the tooltip
private Text _text; 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 //if the tooltip is inside a UI element
private bool _inside; private bool _inside;
// private bool _xShifted, _yShifted = false;
private float width, height;//, canvasWidth, canvasHeight; private float width, height;//, canvasWidth, canvasHeight;
// private int screenWidth, screenHeight; public float YShift,xShift;
private float YShift,xShift; [HideInInspector]
public RenderMode guiMode;
private RenderMode _guiMode;
private Camera _guiCamera; private Camera _guiCamera;
// Use this for initialization public Camera GuiCamera
public void Awake() {
{ get
var _canvas = GetComponentInParent<Canvas>(); {
_guiCamera = _canvas.worldCamera; if (!_guiCamera) {
_guiMode = _canvas.renderMode; _guiCamera = Camera.main;
_rectTransform = GetComponent<RectTransform>(); }
_text = GetComponentInChildren<Text>(); 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()
{
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; _inside = false;
//size of the screen
// screenWidth = Screen.width;
// screenHeight = Screen.height;
xShift = 0f;
YShift = -30f;
// _xShifted = _yShifted = false;
this.gameObject.SetActive(false); this.gameObject.SetActive(false);
} }
//Call this function externally to set the text of the template and activate the tooltip //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) baseTooltipPos = basePos;
{
//set the text and fit the tooltip panel to the text size
_text.text = ttext;
_rectTransform.sizeDelta = new Vector2(_text.preferredWidth + 40f, _text.preferredHeight + 25f); //set the text
if (_text) {
_text.text = ttext;
}
else {
Debug.LogWarning("[ToolTip] Couldn't set tooltip text, tooltip has no child Text component");
}
OnScreenSpaceCamera(); ContextualTooltipUpdate(refreshCanvasesBeforeGetSize);
} }
}
//call this function on mouse exit to deactivate the template //call this function on mouse exit to deactivate the template
public void HideTooltip() public void HideTooltip()
{ {
if (_guiMode == RenderMode.ScreenSpaceCamera) gameObject.SetActive(false);
{ _inside = false;
this.gameObject.SetActive(false);
_inside = false;
}
} }
// Update is called once per frame // Update is called once per frame
void FixedUpdate() void Update()
{ {
if (_inside) if (_inside)
{ {
if (_guiMode == RenderMode.ScreenSpaceCamera) ContextualTooltipUpdate();
{
OnScreenSpaceCamera();
}
} }
} }
//main tooltip edge of screen guard and movement /// <summary>
public void OnScreenSpaceCamera() /// 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.
Vector3 newPos = _guiCamera.ScreenToViewportPoint(Input.mousePosition - new Vector3(xShift, YShift, 0f)); /// Only runs if tooltipTriggersCanForceCanvasUpdate is true
Vector3 newPosWVP = _guiCamera.ViewportToWorldPoint(newPos); /// </summary>
public void RefreshTooltipSize() {
if (tooltipTriggersCanForceCanvasUpdate) {
Canvas.ForceUpdateCanvases();
width = _rectTransform.sizeDelta[0]; if (_layoutGroup) {
height = _rectTransform.sizeDelta[1]; _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)
{
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 // 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)); RectTransformUtility.ScreenPointToWorldPointInRectangle(canvasRectTransform, Vector2.zero, GuiCamera, out screenLowerLeft);
Vector3 upperRight = _guiCamera.ViewportToWorldPoint(new Vector3(1.0f, 1.0f, 0.0f)); RectTransformUtility.ScreenPointToWorldPointInRectangle(canvasRectTransform, new Vector2(Screen.width, Screen.height), GuiCamera, out screenUpperRight);
//check for right edge of screen
val = (newPosWVP.x + width / 2); //check for right edge of screen
if (val > upperRight.x) borderTest = (adjustedNewTTPos.x + width / 2);
if (borderTest > screenUpperRight.x)
{ {
Vector3 shifter = new Vector3(val - upperRight.x, 0f, 0f); shifterForBorders.x = borderTest - screenUpperRight.x;
Vector3 newWorldPos = new Vector3(newPosWVP.x - shifter.x, newPos.y, 0f); adjustedNewTTPos.x -= shifterForBorders.x;
newPos.x = _guiCamera.WorldToViewportPoint(newWorldPos).x;
} }
//check for left edge of screen //check for left edge of screen
val = (newPosWVP.x - width / 2); borderTest = (adjustedNewTTPos.x - width / 2);
if (val < lowerLeft.x) if (borderTest < screenLowerLeft.x)
{ {
Vector3 shifter = new Vector3(lowerLeft.x - val, 0f, 0f); shifterForBorders.x = screenLowerLeft.x - borderTest;
Vector3 newWorldPos = new Vector3(newPosWVP.x + shifter.x, newPos.y, 0f); adjustedNewTTPos.x += shifterForBorders.x;
newPos.x = _guiCamera.WorldToViewportPoint(newWorldPos).x;
} }
// check and solve problems for the tooltip that goes out of the screen on the vertical axis // check and solve problems for the tooltip that goes out of the screen on the vertical axis
//check for upper edge of the screen //check for lower edge of the screen
val = (newPosWVP.y + height / 2); borderTest = (adjustedNewTTPos.y - height / 2);
if (val > upperRight.y) 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)
{ {
Vector3 shifter = new Vector3(0f, 35f + height / 2, 0f); shifterForBorders.y = borderTest - screenUpperRight.y;
Vector3 newWorldPos = new Vector3(newPos.x, newPosWVP.y - shifter.y, 0f); adjustedNewTTPos.y -= shifterForBorders.y;
newPos.y = _guiCamera.WorldToViewportPoint(newWorldPos).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) //failed attempt to circumvent issues caused when rotating the camera
val = (newPosWVP.y - height / 2); adjustedNewTTPos = transform.rotation * adjustedNewTTPos;
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;
}
this.transform.position = new Vector3(newPosWVP.x, newPosWVP.y, 0f); transform.position = adjustedNewTTPos;
this.gameObject.SetActive(true); adjustedTTLocalPos = transform.localPosition;
_inside = true; 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
//screen's 0 = overlay canvas's 0 (always?)
screenLowerLeft = Vector3.zero;
screenUpperRight = canvasRectTransform.sizeDelta;
//check for right edge of screen
borderTest = (newTTPos.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;
}
//remove scale factor for the actual positioning of the TT
adjustedNewTTPos *= canvas.scaleFactor;
transform.position = adjustedNewTTPos;
_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: