In short: How is it meant to implement Tooltips ? Is this even implemented? Or do we need to develop our own solution here?
The UI system doesn't come with anything built-in for tooltips. You can do it yourself with a few simple scripts and setup: Create a Tooltip script with simply a text string in it, that you put on every control that should have a tooltip. Create a script that checks each frame what's underneath the cursor (using the EventSystem). Query the Tooltip component of that object and if present get the text string value from it. Update the visibility and text of a tooltip object in the UI accordingly (possibly the position too if it should follow the cursor). The UI object should be the last child under the Canvas to ensure it's rendered last.
Thanks runevision It's nevertheless a bit odd that there is no inbuild solution as with the old GUI. http://docs.unity3d.com/ScriptReference/GUI-tooltip.html
I struggle with some problems here. It works. But it does not work very well. Even with lateUpdate there is a massive lag behind the mouse position. And i search for a way to impement a timer lag before the popup appears. Means i am at the same situation now as with the old GUI before here. You CAN do everything by yourself. But it's a bad out of the box experience. A experience that every user needs to repeat again now. And the lag behind the mouse position just yells for a inbuild solution that does not lag this horribly behind the mouse position. May i request a inbuild solution?
I have created a video how to do a tooltip in an inventory system: Maybe you have to watch the other videos aswell...Check them out.
Your solution looks a bit complicated, sorry. Nevertheless thanks for the video. Surely useful for some It's not that i don't know how to do it. I am just not this happy that i have to do it by myself. Tooltips is a standard behaviour of a UI. And the mouse lag issue is something that may be fixable with a deeper level access than through LateUpdate. I have two simple scripts at the moment. This one comes at the tooltip object Code (JavaScript): #pragma strict function LateUpdate () { transform.position.x=Input.mousePosition.x; transform.position.y=Input.mousePosition.y; } And this one comes at the button. Code (JavaScript): var mystring: String="Save the created mesh as Obj file"; var tooltip: GameObject; var tooltiptextfield:UI.Text; function pointerenter () { tooltip.SetActive(true); tooltiptextfield.text=mystring; } function pointerexit (){ tooltip.SetActive(false); } Now drag the objects into the slots. Tooltip is the whole tooltip object. Tooltiptext the attached text component. And add two event triggers to each button. PointerEnter and PointerExit. And then call the corresponding loops with the event triggers. And finally adjust the text at each button. Gives a individual tooltip at each button.
use this http://answers.unity3d.com/questions/783279/46-ui-how-to-detect-mouse-over-on-button.html with your transform position
I'm hung up on the Tooltips as well. I have a solution that works rather well, it uses the EventSystems IPointerEnterHandler & IPointerExitHandler to detect when to display the Tooltip. I simply pass a string to the textbox inside my Tooltip Object. It even resizes perfectly now. My issue is positioning the Tooltip. I tried using the localPosition of the RecTransform but it doesn't work reliably if the object triggering the Tooltip is a child in a list. Basically I have a container Listing Skill Objects and while Triggering is perfect, positioning is off. I can run my pointer over every skill being dynamically listed and a different description is displayed but I just cant get the tool tip to position over them. I even tried using a Vector 2 and Vector3 using the Input.mousePosition.x and Input.mousePosition.y coords.
The Z coordinate is a pretty frickin' huge annoyance too. A tightly packed row of buttons with tooltips can be a problem because of the way depth-sorting works in the uGUI. I'd be fine with implementing them myself, since the actual display and object are easy, but the system needs a "frontmost" attribute.
Working on something to solve this issue. My fingers have just started their work so its very early stages. I hope to have something soon.
Any updates on this? We're getting some very odd bugs with 4.6 and wanted to see if there is more formal/supported execution for mouseover tooltips. We have a hacky solution but it has its problems.
So we don't have a native solution for tooltips. That being said you can create your own as a text component, you can then attach a canvas to them and override the sorting. This will allow you to place the the tooltip on top of everything while using the hierarchy for positioning.
Thank you, that helps a good amount. Is there any consistent way to then attach said canvas to the mouse cursor? I've been doing somewhat of a similar solution and approximating based on screen width, but I haven't yet been able to find a consistent/proper way to link it to my mouse cursor location from there. Thanks for any help you can give.
No out of the box tooltip functionality for the new GUI? Ouch. I just started using it, and didn't even think about it until I read this thread. Guess they forgot about it Hopefully ways of doing a decent tooltip behavior will begin to surface after people get acquainted with the system. Or better yet, hopefully Unity devs add it into a future version of the GUI soon.
I personally ended in three little scripts and a somehow wicked object connection to solve the problem. A little timer to give some delay before the tooltip comes up, a script to set the tooltip component to the mouse when it is over a button. And the tooltip text that is attached at the buttons. The call for the tooltip gets called from the event trigger at the buttons then. You can have a look at this project to see how the stuff is connected and set up in my solution. Just download the project file: http://www.reinerstilesets.de/programme/2014-cuhe/ Would be of course much more elegant when there would be a inbuild solution
Thanks for the answers! If anything it just makes us feel better - we thought the answer was obvious and we were just not executing it in the right way.
My idea for implementation: create GO with custom class Tooltip with UIBehaviour parent; then check every update if EventSystem.current.currentSelectedGameObject isnt null if isnt null then fire event and send selected GO; then check if view (i reference to MVC/MVVM approach) component derive from Tooltipable (?) interface if yes enable renderer on tooltip and call .RenderTooltip() function from view component. When selected GO become null again simply disable renderer on tooltip GO Maybe worth a shot? pros: we need only one GO for all tooltip, this will be always on top beacuse we can put this GO as last in Canvas root and structure will be much simpler i think; cons: you have to design your structure under MVC/MVVM approach from beginning or you will have rough time for reorganizing everything...
I made a script that seems to work well for the tooltips (if you want i can share it), the only problem I have is to get the data from the object i have the pointer over without selecting it with a click first. Any hint about that?
Code is always welcome . Without the code you have, its hard to predict where the problem is, but just out of the blue: You did consider a PhysicRaycaster plus implementing IPointerEnterHandler on one of the objects components?
Hi Immanuel, when i get home i can post the code for tooltip! Actually nope, but if you saw my approach to the problem i described in the other post post, i made today ( http://forum.unity3d.com/threads/onpointerover-a-sad-tooltip-story.282472/ ), isn't there any quick way to access the object i am entering from there? I mean, a similar approach (though there is without any flexibility on the dynamic text of the callback) to what one would to from the inspector by adding a pointerenter trigger?
here we go guys, a promise it's a promise. it probably need some polishing in code and optimization, but works perfectly at the moment This is the variant for the screenoverlay version of the canvas (thanks to immanuel we also have the component that makes it appear). Here's a short video of the script at work. The heroes faces are pseudorandomly generated, so the tooltip needs to gather the correct info each time different. http://goo.gl/1GBg27 Tooltip is an item composed by a panel and a child text element. This is where i create the tooltip Code (CSharp): //(in the init method of the tavern) foreach(RectTransform elem in children){ // Debug.Log(elem.tag); if(elem.name=="HeroPanel"){ heroPanel = elem.GetComponent<RectTransform>(); heroPanelGUI = elem.GetComponent<HeroPanelGUI>(); } if(elem.tag=="heroPortrait"){ portraits.Add(elem.GetComponent<Image>()); EventTrigger trig = elem.gameObject.GetComponent<EventTrigger>(); // AddEventTrigger(trig,OnPointerEnter,EventTriggerType.PointerEnter); AddPointerEnterTrigger(trig,OnPointerEnter,EventTriggerType.PointerEnter); AddEventTrigger(trig,OnPointerExit,EventTriggerType.PointerExit); AddEventTrigger(trig,OnPointerClick,EventTriggerType.PointerClick); }else if(elem.tag=="tooltip"){ ttp = elem.GetComponent<ToolTip>(); } } //this is where Immanuel saved me private void AddPointerEnterTrigger(EventTrigger evTrig, UnityAction<BaseEventData> action, EventTriggerType triggerType){ // Create a nee TriggerEvent and add a listener EventTrigger.TriggerEvent trigger = new EventTrigger.TriggerEvent(); AddEventTrigger(evTrig,d => OnPointerEnter(d, evTrig.gameObject),EventTriggerType.PointerEnter); // trigger.AddListener((eventData) => action(eventData)); // you can capture and pass the event data to the listener // Create and initialise EventTrigger.Entry using the created TriggerEvent EventTrigger.Entry entry = new EventTrigger.Entry() { callback = trigger, eventID = triggerType }; // Add the EventTrigger.Entry to delegates list on the EventTrigger evTrig.delegates.Add(entry); } private void OnPointerEnter(BaseEventData dataObject, GameObject hovered){ if(hovered != null && hovered.GetComponent<HeroPortraitGUI>() != null){ ttp.SetTooltip(hovered.GetComponent<HeroPortraitGUI>().heroName); } } This is in the script attached to the tooltip object Code (CSharp): //text of the tooltip Text text; //if the tooltip is inside a UI element bool inside; bool xShifted = false; bool yShifted = false; int textLength; float width; float height; int screenWidth; int screenHeight; float canvasWidth; float canvasHeight; float yShift; float xShift; int canvasMode; public void SetTooltip(string ttext){ //ScreenSpaceOverlay Tooltip if(GUIMode==RenderMode.ScreenSpaceOverlay){ //set the text and fit the tooltip panel to the text size text.text=ttext; this.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(text.preferredWidth+60f,text.preferredHeight+20f); width = this.transform.GetComponent<RectTransform>().sizeDelta[0]; height = this.transform.GetComponent<RectTransform>().sizeDelta[1]; Vector3 newPos = Input.mousePosition-new Vector3(xShift,yShift,0f); //check and solve problems for the tooltip that goes out of the screen on the horizontal axis float val; val=(newPos.x-(width/2)); if(val<=0){ newPos.x+=(-val); } val=(newPos.x+(width/2)); if(val>screenWidth){ newPos.x-=(val-screenWidth); } //check and solve problems for the tooltip that goes out of the screen on the vertical axis val=(screenHeight-newPos.y-(height/2)); if( val<=0 && !yShifted){ yShift=(-yShift+25f); newPos.y+=yShift*2; yShifted=true; } this.transform.position=newPos; this.gameObject.SetActive(true); inside=true; //WorldSpace Tooltip } } public void HideTooltip(){ //ScreenSpaceOverlay Tooltip if(GUIMode==RenderMode.ScreenSpaceOverlay){ xShift = 40f;yShift = -30f; xShifted=yShifted=false; this.transform.position=Input.mousePosition-new Vector3(xShift,yShift,0f); this.gameObject.SetActive(false); inside=false; } } void FixedUpdate () { if(inside){ //ScreenSpaceOverlay Tooltip if(GUIMode==RenderMode.ScreenSpaceOverlay){ Vector3 newPos = Input.mousePosition-new Vector3(xShift,yShift,0f); //check and solve problems for the tooltip that goes out of the screen on the horizontal axis float val; val=(newPos.x-(width/2)); if( val<=0){ newPos.x+=(-val); } val=(newPos.x+(width/2)); if(val>screenWidth){ newPos.x-=(val-screenWidth); } //check and solve problems for the tooltip that goes out of the screen on the vertical axis val=(screenHeight-newPos.y-(height/2)); if(val<=0){ if(!yShifted){ yShift=(-yShift+25f); newPos.y+=yShift*2; yShifted=true; } } this.transform.position=newPos; } } hope it helps guys, if you have question feel free to ask!
I am also slowly adding some features, like the fact that it doesn't go out from the scene (still the vertical flipping is a bit weird, will fix it) even the pointer goes close to the edge, and it resizes according to the text (one line only so far), but it was also a good exercise to learn about the new uGUI (and again, Immanuel saved me )
Awesome! Thanks drHogan - were gonna try this on Monday and see what happens. Thanks so much for sharing! We've been pulling our hair out.
Any update yet on tooltips for the new uGUI? Is it being worked on currently? Will tooltips be ready before the actual Unity 5.0 full release, or do you think it will be ready before then? Would just like to know the state of it and if it's being worked on at all. Hopefully it didn't get forgotten, tooltips will be pretty important for a game like mine
Since I needed tooltips to test something really quick I went to see if there was an implementation in the new uGUI system and stumbled over this thread. Unfortunately none of the custom solutions suited me though, so I quickly built my own, very rough version. It consists of two scripts and a view that is the tooltip. TooltipTrigger This script is put on all the objects you want to trigger the tooltip. It contains the text that should be shown as a public variable. Everything else is handled by the TooltipView. Code (CSharp): using UnityEngine; using UnityEngine.EventSystems; using System.Collections; namespace Sharkbomb.View { public class TooltipTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, ISelectHandler, IDeselectHandler { public string text; public void OnPointerEnter(PointerEventData eventData) { StartHover(new Vector3(eventData.position.x, eventData.position.y - 18f, 0f)); } public void OnSelect(BaseEventData eventData) { StartHover(transform.position); } public void OnPointerExit(PointerEventData eventData) { StopHover(); } public void OnDeselect(BaseEventData eventData) { StopHover(); } void StartHover(Vector3 position) { TooltipView.Instance.ShowTooltip(text, position); } void StopHover() { TooltipView.Instance.HideTooltip(); } } } TooltipView This script is put on a separate uGUI object that is the actual visible tooltip. It's a singleton so the many TooltipTriggers can access it quickly and easily. Code (CSharp): using UnityEngine; using System.Collections; namespace Sharkbomb.View { public class TooltipView : MonoBehaviour { public bool IsActive { get { return gameObject.activeSelf; } } //public CanvasGroup tooltip; public UnityEngine.UI.Text tooltipText; void Awake() { instance = this; HideTooltip(); } public void ShowTooltip(string text, Vector3 pos) { if (tooltipText.text != text) tooltipText.text = text; transform.position = pos; gameObject.SetActive(true); } public void HideTooltip() { gameObject.SetActive(false); } // Standard Singleton Access private static TooltipView instance; public static TooltipView Instance { get { if (instance == null) instance = GameObject.FindObjectOfType<TooltipView>(); return instance; } } } } As said, it's a very simple script. There's a bunch of things it doesn't do. Among them: - It doesn't wait a second before showing the tooltip. - It currently places the tooltip over the object when selecting it via keyboard - The tooltip can leave the boundaries of the screen and become (partially) invisible
Nice implementation @Martin Sharkbomb , would you be ok for me to add this to the UI Extensions bitbucket repo? There is already one ToolTip solution in there but this would be great as an alternate implementation. https://bitbucket.org/ddreaper/unity-ui-extensions *Edit, added to the V1.0.0.2 release
Yeah, sure. Consider it released under Creative Commons. Can you update my info in the header though? Martin Nerurkar // www.martin.nerurkar.de // www.sharkbombs.com Source: http://www.sharkbombs.com/2015/02/10/tooltips-with-the-new-unity-ui-ugui/ Also good to know this thing exists!.
Thanks Martin, will update the credits. The project is under a BSD license which is pretty similar to CC. Basically free to all to use modify and whatever. If you have anymore, feel free to fork the project and submit more. *Note, it got renamed to BoundTooltip as there was another Tooltip control already in the project I also added an Editor Menu option to create it automatically for you
Fair enough, not sure why you called it Bound, but that's not really important. I also noticed you added a check to make sure tooltip is assigned
The other tooltip control that came off the "Useful Scripts" thread is just one script you can attach to anything. This script required two separate components, one for the tooltip and one as an activator. So it seemed to make sense to call it bound because the tooltip has a dependency, that was all I noticed in your vid that your Tooltip GO was also offset (to avoid it being hit), I need to update the editor menu to do that. Either that or add an offset property (or did I do that already, I forget :S)
Man, you rock! I modified a little bit your tooltip solution and it worked perfectly. The modification was for the tooltip running outside the screen when too close to the bottom. It also taught me a little about the Event Trigger system.
Nothing against writing extra code; but for things like tooltips, the expectation was that they would be released pretty quickly. The best way to avoid bugs is to have less code to write; and a tooltip as internal function, reduce the percentage of potential risk On a side note, the new UI system is nice, the hope is that it will function similarly to Visual Studio (auto align, group align, even spacing, even sizing of controls and so on). I just gazed the old system, and the new one feel more "modern"
Code (csharp): public class ToolTip : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler { [Tooltip ("UI components to show or hide.")] [SerializeField] protected GameObject toolTipComponent; [Tooltip ("If true toolTipComponent will be moved to mouse position.")] [SerializeField] protected bool moveTipToMousePosition; protected Vector2 lastPosition; const float ToolTipDelay = 1.25f; const float MouseMoveLeeway = 10.0f; public void OnPointerEnter(PointerEventData eventData) { StopAllCoroutines (); StartCoroutine (CheckForHover ()); } public void OnPointerExit(PointerEventData eventData) { StopAllCoroutines (); Hide(); } public void Show () { if (moveTipToMousePosition) { MoveToolTipToMousePosition (); } toolTipComponent.SetActive (true); StartCoroutine (CheckForCancel()); } public void Hide () { toolTipComponent.SetActive (false); } protected void MoveToolTipToMousePosition() { // Note this works for screen overlay only toolTipComponent.transform.position = new Vector2((int)Input.mousePosition.x, (int) Input.mousePosition.y); } protected IEnumerator CheckForHover () { float timeStill = 0.0f; lastPosition = Input.mousePosition; yield return true; while (timeStill < ToolTipDelay) { if (Vector2.Distance(lastPosition, Input.mousePosition) > MouseMoveLeeway) { timeStill = 0; } else { timeStill += Time.deltaTime; } lastPosition = Input.mousePosition; yield return true; } Show (); } protected IEnumerator CheckForCancel () { lastPosition = Input.mousePosition; yield return true; while (Vector2.Distance(lastPosition, Input.mousePosition) < MouseMoveLeeway) { yield return true; } Hide (); } } Just happened to need a quick tooltip so I whipped this up. I didn't go through everything here, its almost certainly not as advanced as the projects for download, but it has a delay which is what I needed It should be pointed to a tool tip which probably looks like this: ToolTipBase (active = false) - VisualComponent (use a left top positioning so the tip appears at mouse pointer).
Some interesting points in there @JohnnyA might borrow a few and update the existing ToolTip implementations in the UIExtensions project. Only thing I'd change (apart from positioning / activation) would be to not use "StopAllCoroutines". In larger projects this can cause issues, especially if there are other managers using coroutines in a scene. Good stuff, never considering having the delay option and this implementation seems fairly robust
@SimonDarksideJ use whatever you want I was writing for speed (of getting it done... according to my git checkins it took me less than 11 minutes ) not robustness so I'm sure lots can be improved. StopAllCoroutines was pure laziness.
This would save a bunch of hassle and would be very useful especially for PC games, may have to just write something myself then.
@phil-Unity Hi Phil, checking in again after 3 months. Will this ever be included as part of the UI framework in the future? I saw your post in this thread a year ago: so I'm assuming it will be?