Resizing a DirectGuiWidget doesn't update position of text

For the sake of others coming into the thread, and for the sake of completeness in it, let me start by quoting my explanation of this behaviour:

I think that there’s a caveat here: changing the frame-size doesn’t actually affect where the button thinks its “left”, “right”, and “centre” are. Instead, it’s the other way around: the frame-size seems to be specified relative to the text-anchor.

You can see this in action if you construct buttons with left- or centre- anchors, then change their frame-sizes such that they have a left-extent of zero. (Which should thus tell you where the buttons think that zero is.) You should find that in buttons with a left text-alignment, the left-hand extent of the button ends up at the left of the text, and that in buttons with a centre-alignment, the left-hand extent ends up at the centre of the text.

It’s arguably not intuitive, but it does seem to be the way that it works. ^^;

Original link.

That said, I see two potential workarounds:

  1. You could perhaps alter the applied frame-size based on the assigned alignment.
    • That is, if the widget is set to be centre-aligned, you could offset the horizontal elements of the frame-size such that they’re centred on zero. Similarly, if the widget is set to be left-aligned, you could offset the horizontal elements of the frame-size such that zero is on the left of the frame.
  2. You could perhaps set the “text_pos” keyword to offset the text as appropriate.
    • That is, if the widget is set set to be left-aligned, you might set the horizontal element of the “text_pos” keyword to the left-most extent of the new frame-size.

Quick examples of these approaches:

(1)
(As it turns out, it seems that you can’t directly query the “text_align” keyword at the moment. I’ve opened a GitHub issue for this matter here.)

from panda3d.core import TextNode

from direct.showbase import ShowBase as showBase
from direct.gui.DirectGui import DirectButton

class Game(showBase.ShowBase):

    def __init__(self):
        showBase.ShowBase.__init__(self)

        self.accept("escape", base.userExit)
        self.accept("space", self.resize,
                    extraArgs = [(-2, 2, -1, 1)])

        self.btn = DirectButton(text = "Kitten",
                                text_align = TextNode.ALeft,
                                scale = 0.07)

    def resize(self, newFrameSize):
        print ("Resizing")

        textNode = self.btn.guiItem.getTextNode()
        print (textNode.align == TextNode.ALeft, TextNode.ACenter)

        if textNode.align == TextNode.ALeft:
            width = abs(newFrameSize[1] - newFrameSize[0])
            newFrameSize = (
                0,
                width,
                newFrameSize[2],
                newFrameSize[3]
            )

        self.btn["frameSize"] = newFrameSize

app = Game()
app.run()

(2)

from panda3d.core import TextNode

from direct.showbase import ShowBase as showBase
from direct.gui.DirectGui import DirectButton

class Game(showBase.ShowBase):

    def __init__(self):
        showBase.ShowBase.__init__(self)

        self.accept("escape", base.userExit)
        self.accept("space", self.resize)

        self.btn = DirectButton(text = "Kitten",
                                text_align = TextNode.ALeft,
                                scale = 0.07)

    def resize(self):
        print ("Resizing")

        self.btn["frameSize"] = (-2, 2, -1, 1)
        self.btn["text_pos"] = (-2, 0)
        
app = Game()
app.run()
1 Like