toga icon indicating copy to clipboard operation
toga copied to clipboard

Widgets within an OptionContainer are too large if a window is shown prior to the container being assigned to the window

Open kcoombs opened this issue 9 months ago • 3 comments

Describe the bug

On Windows, a behavior that was introduced in Toga 0.5.0 in which (at least) Label and Button elements within an OptionContainer are too large if the OptionContainer is assigned to a Window after the Window has already been shown.

Here is code to reproduce:

import toga

class TogaApp(toga.App):
    def startup(self) -> None:
        self.main_window = toga.MainWindow()
        self.main_window.show()

        container_box = toga.Box()
        container_box.add(toga.Label("TEST Label", background_color="lightblue"))
        container_box.add(toga.Button("TEST Button"))
        home_tab = toga.OptionItem(text="Home", content=container_box,)
        option_container = toga.OptionContainer(content=[home_tab])

        # self.main_window.hide()
        self.main_window.content = option_container
        # self.main_window.show()


def main():
    return TogaApp("Toga App", 'org.beeware.togaapp')


if __name__ == "__main__":
    main().main_loop()

Here is an example of a window produced by the foregoing code:

Image

And here is an example if you uncomment the hide and show commands:

Image

Steps to reproduce

  1. Run the povided code on Windows and with Toga 0.5.0
  2. The rendered Label and Button elements are too large.

Expected behavior

The window produced by this code should be the same regardless of when the window is actually shown.

Screenshots

No response

Environment

  • Operating System: Windows 11
  • Python version: 3.12.7
  • Software versions:
    • Toga: 0.5.0

Logs


Additional context

I ran into this when reassigning the MainWindow's content. E.g., from an initial "loading" box to its final post-loading content.

kcoombs avatar Mar 20 '25 14:03 kcoombs

Thanks for the report. I'm guessing that because the widget is hidden when the content switch happens, it's not getting a layout request triggered appropriately when it becomes visible. It's also possibly related to fact that the option panel is a "subcontainer" - the internal layout of those subcontainers are disjointed from the main container, so it's possible the layout signal caused by being shown isn't being passed down correctly. More investigation is required.

freakboy3742 avatar Mar 20 '25 21:03 freakboy3742

I belive I have narrowed in on the cause of the padding problem (Windows, Toga >= 0.5.0). It seems to be related to https://github.com/beeware/toga/pull/2155 (Improved DPI Scaling on Windows and Fixed related Bugs), added in Toga 0.5.0. Notably, the padding behavior described above only happens at Hi-DPI resolution. At low-DPI resolution, the padding on widgets is drawn properly. These screenshots (executing reproduction code above) are from the same Windows VM and code base, with the only difference being whether I'm connected to via RDP it at Hi-DPI or low-DPI:

Low-DPI: Image Hi-DPI Image

I suspect that if an OptionContainer is built out of view, or within a not completely build parent container, in a Hi-DPI environment, its widgets are being built with the wrong DPI. I've seen this in the situation described above and with the reproduction code. I've also seen this when one OptionContainer is nested within another OptionContainer (the widgets within the parent container is drawn fine, but the padding is off for widgets within the child OptionContainer). For example:

Low-DPI: Image Hi-DPI: Image

kcoombs avatar May 20 '25 15:05 kcoombs

I belive I have narrowed in on the cause of the padding problem (Windows, Toga >= 0.5.0). It seems to be related to #2155 (Improved DPI Scaling on Windows and Fixed related Bugs), added in Toga 0.5.0. Notably, the padding behavior described above only happens at Hi-DPI resolution.

That is some really helpful debugging - thanks for all your work on this.

As for how to fix it.... 😬

freakboy3742 avatar May 20 '25 20:05 freakboy3742