DirectGUI interfering with mouse wheel input

Return to General Discussion

DirectGUI interfering with mouse wheel input

Postby preusser » Sun Apr 22, 2012 1:15 pm

I have a DirectScrolledFrame and I've assigned my mouse wheel to move the DirectScrolledFrame thumb. It only works when the mouse cursor is *not* on the frame. Why and what can be done?
Last edited by preusser on Wed May 09, 2012 2:08 am, edited 1 time in total.
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am

Postby rdb » Mon Apr 23, 2012 9:50 am

The default behaviour is that DirectGui elements suppress mouse events (to prevent a click on a GUI button from translating to a click event in the game screen, for instance).
Either bind specifically to a DirectGui event (like object.bind(DGG.B1CLICK)) or disable this behaviour by setting suppressMouse = True in the constructor of the DirectScrolledFrame.
rdb
 
Posts: 9418
Joined: Mon Dec 04, 2006 5:58 am
Location: Netherlands

Postby preusser » Tue Apr 24, 2012 12:19 pm

Thanks. I hadn't noticed the "suppressMouse" argument.
But I can't find any var for the mouse wheel_up and wheel_down. http://www.panda3d.org/reference/1.8.0/ ... da1e047b63

Also, this leads me to another question: why don't the "not-clickable" parts of the GUI classes *not* take into account that argument? I would like to disable camera controls even when the mouse cursor is on a DirectFrame or DirectLabel...
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am

Postby drwr » Tue Apr 24, 2012 5:47 pm

There's not a DGG symbol for the wheel motion, so you can't bind for that explicitly; but the suppressMouse idea should work, though I think you want to set suppressMouse = False, meaning to allow the wheel_up and wheel_down events (as well as all other mouse button events) to be seen even though the mouse is over the frame.

why don't the "not-clickable" parts of the GUI classes *not* take into account that argument?

If a frame isn't clickable, Panda doesn't create a frame for it, and so doesn't track whether the mouse is over it or not. If you want this behavior, you have to make it clickable by passing state = DGG.NORMAL.

David
drwr
 
Posts: 11425
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby preusser » Wed Apr 25, 2012 1:11 am

If a frame isn't clickable, Panda doesn't create a frame for it, and so doesn't track whether the mouse is over it or not. If you want this behavior, you have to make it clickable by passing state = DGG.NORMAL.

Okay, I guess it wouldn't be bad to have things clickable when pressEffect is set to None.

As for the suppressMouse option, that works, but I also don't want my camera controls to interfere with the GUI.
So can I ask for a feature request? Right now in my character selection screen, if the player clicks on one character button, the camera almost always slightly rotates.
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am

Postby drwr » Wed Apr 25, 2012 11:48 am

Well, you can always write your camera control class to check first if the mouse is over one of the clickable regions before it does anything. You can use base.mouseWatcherNode.isOverRegion() or getOverRegion().

David
drwr
 
Posts: 11425
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby preusser » Sun Apr 29, 2012 9:09 am

There seems to be a problem with your solution.

I can indeed set suppressMouse to False in my GUI objects, but still suppress the camera controls in my task.

However, if I click on one button, keep the mouse button clicked and move to another (right next to it, no gaps), the base.mouseWatcherNode.isOverRegion() suddenly returns False.
I don't know if this is a bug, or an expected behavior, but it makes the solution unusable to me.
Same behavior with base.mouseWatcherNode.getOverRegion().

Heres an example:
Code: Select all
from panda3d.core import *
import direct.directbase.DirectStart
from direct.gui.DirectGui import *

def mytask(task):
   print base.mouseWatcherNode.isOverRegion()
   return task.cont
taskMgr.add(mytask, 'mytask')

button = DirectButton(text = 'AAAA', suppressMouse = False)
button2 = DirectButton(text = 'BBBB', suppressMouse = False)
button2.setX(0.5)

scene = loader.loadModel('environment')
scene.reparentTo(render)

run()

Click on button "AAAA", keep the mouse button clicked and move to button "BBBB". They are on top of each other, but even if there was a gap, you still get False when you are on button "BBBB".

Also, even if there wasn't this issue, there would still be the problem of enabling camera controls when mouse leaves the button, even though the mouse button is still held down. That's not a standard behavior.
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am

Postby drwr » Mon May 07, 2012 1:24 pm

This is the intended behavior; it's meant to handle the case of clickable objects on the desktop, which behave in this way: when you click on a Windows GUI button, for instance, and drag the mouse off of the button while the mouse button is still held, you cannot trigger any other buttons you drag off. The mouse is "captured" or still considered held by the original button, and the MouseWatcher follows this model.

If you require different behavior, you can always write a task to implement the precise behavior you require. :)

David
drwr
 
Posts: 11425
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby preusser » Mon May 07, 2012 1:38 pm

I'm not really convinced that everything is as it should be now...
When you press a button and move out of it you don't want camera controls to work again until you have let go of it.

So what is the solution now? I hope you don't mean not using DirectGUI at all.
Last edited by preusser on Mon May 07, 2012 1:42 pm, edited 1 time in total.
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am

Postby drwr » Mon May 07, 2012 1:41 pm

I'm unable to parse your sentence: do you *want* camera controls to be active while the mouse button is still held, or do you want them to be suppressed?

In either case, you can get the exact behavior you need by writing your camera controls to examine the mouse position information directly from the window, instead of getting it from the MouseWatcher. The mouse information reported by the MouseWatcher is filtered by DirectGui. If you don't want this, go to the source. You can still use DirectGui.

David
drwr
 
Posts: 11425
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby preusser » Mon May 07, 2012 1:45 pm

drwr wrote:I'm unable to parse your sentence: do you *want* camera controls to be active while the mouse button is still held, or do you want them to be suppressed?

I don't want my camera controls to work when: 1. I've pressed a button, 2. not released the button 3. and moved the mouse cursor outside of the button's frame.

With your old solution I could tell my camera manager to not work when mouse is on a button (by checking base.mouseWatcherNode.isOverRegion() in the camera manager class and suppressMouse set to False in my GUI objects), but have the mouse wheel work, however then I'll get the above issue.

I'm not really sure how getting the mouse position on the window will get me anything with DirectGUI.
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am

Postby drwr » Mon May 07, 2012 3:38 pm

In that case, why not just check MouseWatcher.isOverRegion() in your camera controls task? While the mouse button is held, the mouse is considered to be still over its original region, so isOverRegion() will continue to return true.

David
drwr
 
Posts: 11425
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby preusser » Tue May 08, 2012 5:20 am

drwr wrote:In that case, why not just check MouseWatcher.isOverRegion() in your camera controls task? While the mouse button is held, the mouse is considered to be still over its original region, so isOverRegion() will continue to return true.

That's the solution you gave me previously, and that's what doesn't work. I must be not clear what the problem is. When you click on a button, don't let go of the button and move the cursor out of it's frame, MouseWatcher.isOverRegion() in fact starts returning False.
Here's an example:
Code: Select all
from panda3d.core import *
import direct.directbase.DirectStart
from direct.gui.DirectGui import *

def mytask(task):
   print base.mouseWatcherNode.isOverRegion()
   return task.cont
taskMgr.add(mytask, 'mytask')

button = DirectButton(text = 'AAAA', suppressMouse = False)

scene = loader.loadModel('environment')
scene.reparentTo(render)

run()
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am

Postby drwr » Tue May 08, 2012 3:03 pm

Hmm, you're right; my apologies. Looks like it would be helpful to have an additional interface on MouseWatcher that would return the currently focused region.

Lacking that interface, I suppose you would have to track mouse button up/down events to infer whether the cursor is currently focused on a region or not.

David
drwr
 
Posts: 11425
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby preusser » Wed May 09, 2012 1:42 am

If it was possible, a "WHEEL" variable in DirectGuiGlobals would be a nicer addition, because it would result in cleaner code. Though I say this because I can't think of any other use for checking the currently focused region.

As for the last workaround you mentioned, how exactly do you think of using it? As the button 1 click is already used by the camera manager. This isn't a keyboard button to at least check MouseWatcher.isButtonDown(KeyboardButton.button())
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am

Postby drwr » Wed May 09, 2012 6:46 pm

I meant to listen for "mouse0" and "mouse0-up" events. When you receive "mouse0" you can check MouseWatcher.isOverRegion() at that time. If it returns true, assume the mouse is off-limits until you receive mouse0-up.

David
drwr
 
Posts: 11425
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby preusser » Thu May 10, 2012 7:42 am

Oh, that's actually a pretty simple solution. :)

But even here there is some problem. If I use the mouse wheel when mouse cursor is on the decButton or incButton of DirectScrolledFrame, the thumb always moves in one direction, which seems like the buttons are triggered instead. And doesn't seem to work when mouse cursor is on the thumb itself.

Unrelated to my new problem, I still think something like
Code: Select all
DirectScrolledFrame.bind(DGG.WHEEL)

would be cleaner and more convenient as people wouldn't have to worry of writing the appropriate code in their camera manager classes and worrying about setting "suppressMouse" to False in their GUI objects.

I know that there is a list of more important stuff in the schedule, so maybe I could post this in launchpad for future reference, if you agree.
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am

Postby drwr » Thu May 10, 2012 11:13 am

Sure; I think you're right that adding explicit support for the mouse wheel is a useful feature for DirectGui. Please do add it to the Launchpad.

David
drwr
 
Posts: 11425
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby preusser » Thu May 10, 2012 11:51 am

Okay.

Any ideas about my new problem?
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am

Postby drwr » Thu May 17, 2012 11:50 am

I don't know about that. Actually, I'm surprised that DirectGui does anything at all when you twiddle the mouse wheel, since it was mostly written back in the days before mouses had wheels.

Perhaps this is something you can track down further within the Python code?

David
drwr
 
Posts: 11425
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby preusser » Sat May 19, 2012 11:45 am

Not to say that I studied the DirectGui modules, but adding these two lines in direct/gui/DirectGuiGlobals.py after line 72 seems to do the trick.
Code: Select all
WHEELUP = PGButton.getReleasePrefix() + MouseButton.wheelUp().getName() + '-'
WHEELDOWN = PGButton.getReleasePrefix() + MouseButton.wheelDown().getName() + '-'


Code: Select all
from panda3d.core import *
import direct.directbase.DirectStart
from direct.gui.DirectGui import *

button = DirectButton(text = "Hello")

def myfunc(event): print "Wheel moved"
button.bind(DGG.WHEELUP, myfunc)
button.bind(DGG.WHEELDOWN, myfunc)

run()


I think the mouse wheel suppression is probably set in the low-level C++ classes. Just had a quick glance though.
preusser
 
Posts: 520
Joined: Sun Mar 27, 2011 10:07 am


Return to General Discussion

Who is online

Users browsing this forum: No registered users and 0 guests