Mixed BoundTooltip with ToolTip, added Screenspace Overlay support
parent
37aec29aa0
commit
6c639c7f51
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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,145 +23,293 @@
|
|||
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;
|
||||
|
||||
// Use this for initialization
|
||||
public void Awake()
|
||||
{
|
||||
var _canvas = GetComponentInParent<Canvas>();
|
||||
_guiCamera = _canvas.worldCamera;
|
||||
_guiMode = _canvas.renderMode;
|
||||
_rectTransform = GetComponent<RectTransform>();
|
||||
public Camera GuiCamera
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_guiCamera) {
|
||||
_guiCamera = Camera.main;
|
||||
}
|
||||
|
||||
_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;
|
||||
|
||||
//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
|
||||
_text.text = ttext;
|
||||
baseTooltipPos = basePos;
|
||||
|
||||
_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
|
||||
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()
|
||||
{
|
||||
Vector3 newPos = _guiCamera.ScreenToViewportPoint(Input.mousePosition - new Vector3(xShift, YShift, 0f));
|
||||
Vector3 newPosWVP = _guiCamera.ViewportToWorldPoint(newPos);
|
||||
/// <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();
|
||||
|
||||
width = _rectTransform.sizeDelta[0];
|
||||
height = _rectTransform.sizeDelta[1];
|
||||
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)
|
||||
{
|
||||
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
|
||||
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));
|
||||
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
|
||||
val = (newPosWVP.x + width / 2);
|
||||
if (val > upperRight.x)
|
||||
|
||||
//check for right edge of screen
|
||||
borderTest = (adjustedNewTTPos.x + width / 2);
|
||||
if (borderTest > screenUpperRight.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;
|
||||
shifterForBorders.x = borderTest - screenUpperRight.x;
|
||||
adjustedNewTTPos.x -= shifterForBorders.x;
|
||||
}
|
||||
//check for left edge of screen
|
||||
val = (newPosWVP.x - width / 2);
|
||||
if (val < lowerLeft.x)
|
||||
borderTest = (adjustedNewTTPos.x - width / 2);
|
||||
if (borderTest < screenLowerLeft.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;
|
||||
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 and solve problems for the tooltip that goes out of the screen on the vertical axis
|
||||
|
||||
//check for upper edge of the screen
|
||||
val = (newPosWVP.y + height / 2);
|
||||
if (val > upperRight.y)
|
||||
//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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
//failed attempt to circumvent issues caused when rotating the camera
|
||||
adjustedNewTTPos = transform.rotation * adjustedNewTTPos;
|
||||
|
||||
this.transform.position = new Vector3(newPosWVP.x, newPosWVP.y, 0f);
|
||||
this.gameObject.SetActive(true);
|
||||
_inside = true;
|
||||
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
|
||||
//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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: abe02588cca16964c8571b21eefea5d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Reference in New Issue