DirectButton.bind() issue

sample code:

import panda3d.core
from direct.showbase.ShowBase import ShowBase
import direct.gui.DirectGui

base = ShowBase()

button = direct.gui.DirectGui.DirectButton(text="Test")
button.set_scale(2)

def highlight(state, mouse_position):
	if state == True:
		button.set_color_scale(1.5,1.5,1.5,1)
	else:
		button.clear_color_scale()
		
button.bind(direct.gui.DirectGui.DGG.WITHIN, highlight, extraArgs = [True])
button.bind(direct.gui.DirectGui.DGG.WITHOUT, highlight, extraArgs = [False])

base.run()


Hover your mouse on the button for it to “get highlighted”, now move the mouse back for it to revert to normal color.

The problem is if you hower on the button, then rapidly move the mouse cursor outside of the window, the button.bind(direct.gui.DirectGui.DGG.WITHOUT) does not get triggered, and the button remains the same state it was set by button.bind(direct.gui.DirectGui.DGG.WITHIN) .
Even more so, if you then move the mouse cursor back into the window but not over the button, button.bind(direct.gui.DirectGui.DGG.WITHOUT) is still not triggered.

Is this a bug? Or expected behavior?

Use ENTER and EXIT for this use case. They work properly.

That said, it does look like a bug that WITHIN and WITHOUT don’t produce the expected behaviour, please file a bug for this on the issue tracker.

As an aside, note that you can probably achieve this highlight effect without custom events, by using the state system. But I’d not be sure how exactly off the top of my head.

2 Likes

I think that one can just pass a tuple of colours for the objects “frameColour”, allowing one to set a per-state tint.

It does have the disadvantage that one can, I think, not brighten the button in this way: its colour will always be at most as bright as the base art applied to it. But if the button is designed with this in mind, it may yet work.

In fact, I just tried it, and indeed it works. See this little demonstrative program:

from direct.showbase.ShowBase import ShowBase

from panda3d.core import Vec4
from direct.gui.DirectGui import DirectButton

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.win.setClearColor(Vec4(0, 0, 0, 1))

        stateColours = ( (0.1, 0.7, 0.1, 1), # Normal
                         (1, 1, 1, 1), # Pressed
                         (0.3, 1, 0.6, 1), # Hovered
                         (0.2, 0.2, 0.2, 1), # Disabled
            )

        btn = DirectButton(text = "MEW", frameColor = stateColours, scale = 0.2)


app = Game()
app.run()
1 Like

Replying to both points,

DGG.ENTER and DGG.EXIT do not have the issues I mentioned and seem to work fine. I’ll use them instead, and file the bug report regarding to DGG.WITHIN and DGG.WITHOUT.

Regarding DirectButton[“frameColor”] . it’s not a good solution for this reason:
If you already do DirectButton[“geom”].set_color_scale() because your program/game has UI themes which change the color of the buttons, then “frameColor” gets overwritten by your theme color setting code, I am assuming because DirectButton frameColor uses set_color() instead of set_color_scale() internally, and if it used set_color_scale() instead I believe it would work in this scenario.

Thanks

You could perhaps have your themes set the “frameColor” tuple rather than the colour-scale; that should allow both to work, I imagine. (And would give you a bit of extra flexibility in the colouring of your themes.)

You could. The thing was set_color_scale() also works with purely NodePath GUI elements (not Direct element), but I guess I can check the type of the element in the color setting function.

1 Like