Author Topic: Detect if the mouse leaves the panel that contains a button  (Read 13930 times)

deckard

  • Guest
Detect if the mouse leaves the panel that contains a button
« on: November 28, 2012, 12:43:40 PM »
Hi,



  1. void Start(){
  2.     UIEventListener.Get(mainPanel).onHover = OnHoverTip;
  3. }
  4. void OnHoverTip(GameObject g,bool b){
  5.    //b = false when the mouse is over the button
  6. }
  7.  
I want to detect if the mouse leaves the panel to close it.

Problem, when I put the mouse over the button, the collider changes (Collider panel to Collider panel), and Onhover returns false
The solution is to check all the colliders?

JRoch

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 140
    • View Profile
Re: Detect if the mouse leaves the panel that contains a button
« Reply #1 on: November 28, 2012, 01:36:36 PM »
You will need to create a script that you attach to the panel that enumerates and stores all of its children's instanceID, as well as the panel's own.  I recommend using a hashtable or dictionary for storage, so it's fast.  Then, your panel script that checks to see if the mouse is still hovering simply needs to check if the currently hovered target instanceID is the panel itself or one of those children.  If so, do nothing.  If not, close the panel.  I also recommend adding a small window of opportunity for the mouse to re-hover the window, as sometimes the user will not be accurate and the mouse will stray off the window for a fraction of a second.

I wrote a fairly general panel manager with this type of functionality for my own project, which you will want to do as well... so you can easily add it to any panel you create that you want to behave in this fashion.

deckard

  • Guest
Re: Detect if the mouse leaves the panel that contains a button
« Reply #2 on: November 28, 2012, 04:14:59 PM »
Hi Jroch !

Good idea !!

I'll try something like that

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. public class UIPanelController : MonoBehaviour {
  6.        
  7.        
  8.         public UIPanel panel;
  9.         public Camera UICamera;
  10.        
  11.         private  List<int> UIObjectInstanceIds = new List<int>();
  12.        
  13.         void Start () {
  14.        
  15.                 UIObjectInstanceIds.Add(panel.GetInstanceID());
  16.                 foreach(Transform child in panel.transform){
  17.                         UIObjectInstanceIds.Add(child.GetInstanceID());
  18.                         Debugger.get.log(child.GetInstanceID().ToString());
  19.                 }
  20.                
  21.         }
  22.        
  23.         // Update is called once per frame
  24.         void Update () {
  25.                 RaycastHit hit ;
  26.                 if(Physics.Raycast(UICamera.ScreenPointToRay(Input.mousePosition), out hit)){
  27.                         if(!UIObjectInstanceIds.Contains(hit.transform.GetInstanceID()))outOfPanel();
  28.                 }
  29.         }
  30.  
  31.         void outOfPanel(){
  32.                 // Disable panel
  33.         }
  34. }

JRoch

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 140
    • View Profile
Re: Detect if the mouse leaves the panel that contains a button
« Reply #3 on: November 28, 2012, 08:06:45 PM »
You don't have to do your own raycast event, you can just use UICamera.lasthit

But, yeah, you pretty much got it.


deckard

  • Guest
Re: Detect if the mouse leaves the panel that contains a button
« Reply #4 on: November 29, 2012, 04:11:06 AM »
Thank you, I did not know this method!


  1. void Update () {
  2.                 if(!UIObjectInstanceIds.Contains(UICamera.lastHit.transform.GetInstanceID()))outOfPanel();     
  3.         }
  4.  

But UICamera.lastHit gives me all the time the id of the UI ROOT...is this normal?

deckard

  • Guest
Re: Detect if the mouse leaves the panel that contains a button
« Reply #5 on: November 29, 2012, 04:19:46 AM »
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. public class UIPanelController : MonoBehaviour {
  6.        
  7.        
  8.         public UIPanel panel;
  9.         public delegate void OutOfPanel(bool b);
  10.         public OutOfPanel outOfPanel;
  11.        
  12.         private  List<int> UIObjectInstanceIds = new List<int>();
  13.        
  14.         void Start () {
  15.        
  16.                 UIObjectInstanceIds.Add(panel.transform.GetInstanceID());
  17.                 UIObjectInstanceIds.Add(this.transform.GetInstanceID());// this = UI ROOT
  18.        
  19.                 foreach(Transform child in panel.transform){
  20.                         UIObjectInstanceIds.Add(child.GetInstanceID());
  21.                 }
  22.  
  23.         }
  24.  
  25.         void Update () {
  26.                 bool b=true;
  27.                 if(!UIObjectInstanceIds.Contains(UICamera.lastHit.transform.GetInstanceID()))b=false;  
  28.                 outOfPanel(b);
  29.         }
  30.        
  31.  
  32. }
It works very well.
But collect all the children useful?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Detect if the mouse leaves the panel that contains a button
« Reply #6 on: November 29, 2012, 07:11:35 AM »
Why are you doing this?

NGUITools.FindInParents<UIPanel>(hitCollider.gameObject) will tell you the panel. If it's not your popup panel, close it.

deckard

  • Guest
Re: Detect if the mouse leaves the panel that contains a button
« Reply #7 on: November 29, 2012, 01:45:38 PM »
Thank Jroch & Aren !!!!

deckard

  • Guest
Re: Detect if the mouse leaves the panel that contains a button
« Reply #8 on: December 04, 2012, 08:41:53 AM »
Hi Aren,

I have bugs, I think did not understand your solution :(
I did this:

  1.    void Update () {
  2.         RaycastHit hit ;
  3.         if(Physics.Raycast(UICamera.ScreenPointToRay(Input.mousePosition), out hit)){
  4.             if(NGUITools.FindInParents<UIPanel>(hit.collider.gameObject) != panel)outOfPanel(true);
  5.                         else outOfPanel(false);
  6.         }
  7.     }

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Detect if the mouse leaves the panel that contains a button
« Reply #9 on: December 04, 2012, 10:23:45 AM »
Don't raycast anything. NGUI already does all the raycasting, so you don't have to do anything. That line I posted is literally all you need:
  1. if (yourPanel != NGUITools.FindInParents<UIPanel>(UICamera.lastHit.collider.gameObject)) <Do something>
You will want to check for UICamera.lastHit.collider != null, of course.

JRoch

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 140
    • View Profile
Re: Detect if the mouse leaves the panel that contains a button
« Reply #10 on: December 04, 2012, 10:58:02 AM »
I guess I re-invented the wheel since the implications of any given member function is not immediately apparent when you're first starting off with NGUI.  Time to go back and re-factor some of my common classes.

JRoch

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 140
    • View Profile
Re: Detect if the mouse leaves the panel that contains a button
« Reply #11 on: December 04, 2012, 02:52:40 PM »
Aren, I'm having to compare the gameObject.name property against either lasthit.collider.gameObject or .hoveredObject.  For some odd reason the gameObjects and InstanceIDs are different, even though resolving the .name yields the same object name.  And these gameobjects that have UIPanel are definitely unique and have unique names.  I just don't get why I'm not getting the same object reference.

Here's the skeleton of the function I'm using to check if the mouse has left a given panel:

  1.         if (hideIfLosesMouseFocus)
  2.         {
  3.             _ObjectHovered = (UICamera.hoveredObject != null);
  4.  
  5.             if (!_ObjectHovered || this.gameObject.name != NGUITools.FindInParents<UIPanel>(UICamera.hoveredObject).name)
  6.             {
  7.  
  8.                 if (!_focusLost)
  9.                 {
  10.                     _focusLost = true;
  11.                     _hideAtTime = DateTime.Now + TimeSpan.FromMilliseconds(500);
  12.                 }
  13.                 else
  14.                 {
  15.                     if (DateTime.Now > _hideAtTime)
  16.                     {
  17.                         NGUITools.SetActive(this.gameObject, false);
  18.                         _focusLost = false;
  19.                     }
  20.                 }
  21.  
  22.  
  23.             }
  24.             else
  25.             {
  26.                 // hovering within panel
  27.                 _focusLost = false;
  28.             }
  29.  

This works, but I'd be happier if I could avoid using the .name property, since there is no guarantee of uniqueness there.
« Last Edit: December 04, 2012, 02:59:55 PM by JRoch »

JRoch

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 140
    • View Profile
Re: Detect if the mouse leaves the panel that contains a button
« Reply #12 on: December 04, 2012, 03:03:57 PM »
Aha.  The returned gameObject reference from FindInParents<> is actually a reference to the component, not the parent gameObject.  So as long as you compare:

NGUITools.FindInParents<UIPanel>(UICamera.hoveredObject).gameObject

My logic will then work.

It's not completely clear from FindInParents calling structure that it is returning a component reference, not the owning gameObject's reference.  I had to logically work out what was actually being passed back.  Might want to be a bit more explicit in the function header comment?   (At least for noobs.)

deckard

  • Guest
Re: Detect if the mouse leaves the panel that contains a button
« Reply #13 on: December 05, 2012, 04:38:57 AM »
I have done like this and it works:

  1. private List<UIPanel> uiPanels = new List<UIPanel>();
  2.  
  3.         void Start(){
  4.                 searchPanel(transform, ref uiPanels);
  5.         }
  6.  
  7.         private void searchPanel (Transform t, ref List<UIPanel> uiPanels){
  8.                 foreach(Transform child in t){
  9.                         UIPanel uiPanel = child.GetComponent<UIPanel>();
  10.                         if(uiPanel != null)uiPanels.Add(uiPanel);
  11.                         if(child.childCount > 0)searchPanel(child, ref uiPanels);
  12.                 }      
  13.         }
  14. void Update () {
  15.                
  16.                 UIPanel hoveredPanel = NGUITools.FindInParents<UIPanel>(UICamera.hoveredObject);
  17.                 if (!uiPanels.Contains(hoveredPanel)){
  18. <mouse is out !>
  19. }
  20.  
  21. }
« Last Edit: December 05, 2012, 04:45:06 AM by deckard »

deckard

  • Guest
Re: Detect if the mouse leaves the panel that contains a button
« Reply #14 on: December 31, 2012, 11:06:38 AM »
Hi,

Just another much simpler method that I found :

  1. if( UICamera.hoveredObject == null || !UICamera.hoveredObject.transform.IsChildOf(Parent)) //The mouse is out a selected Parent

Must widgets that must detect are all in the same gameobject (parent)