Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contents are laid out before container size is known #1624

Closed
mhsmith opened this issue Oct 18, 2022 · 2 comments · Fixed by #1969
Closed

Contents are laid out before container size is known #1624

mhsmith opened this issue Oct 18, 2022 · 2 comments · Fixed by #1969
Labels
android The issue relates to Android mobile support. bug A crash or error in behavior. windows The issue relates to Microsoft Windows support.

Comments

@mhsmith
Copy link
Member

mhsmith commented Oct 18, 2022

Run the following app (based on #1604):

import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW

class AFV(toga.App):

    def startup(self):
        self.main_window = toga.MainWindow(title=self.formal_name)

        box_test = toga.Box(style=Pack(direction=COLUMN, padding=5))
        self.label_1 = toga.Label('TESTE 1')
        self.lineEdit_1 = toga.TextInput()
        self.label_2 = toga.Label('TESTE 2')
        self.lineEdit_2 = toga.TextInput()
        self.label_3 = toga.Label('TESTE 3')
        self.lineEdit_3 = toga.TextInput()
        self.label_4 = toga.Label('TESTE 4')
        self.lineEdit_4 = toga.TextInput()
        self.label_5 = toga.Label('TESTE 5')
        self.lineEdit_5 = toga.TextInput()
        self.label_6 = toga.Label('TESTE 6')
        self.lineEdit_6 = toga.TextInput()

        box_test.add(self.label_1, self.lineEdit_1,
                     self.label_2, self.lineEdit_2,
                     self.label_3, self.lineEdit_3,
                     self.label_4, self.lineEdit_4,
                     self.label_5, self.lineEdit_5,
                     self.label_6, self.lineEdit_6)
        self.container = toga.ScrollContainer(horizontal=True, vertical=True)
        self.container.content = box_test

        box_outer = toga.Box(style=Pack(direction=ROW), children=[
            toga.Box(style=Pack(flex=1, background_color="red")),
            toga.Box(style=Pack(flex=3, direction=COLUMN), children=[
                toga.Box(style=Pack(background_color="green", flex=1)),
                self.container
            ])
        ])
        self.container.style.update(flex=1)

        self.main_window.content = box_outer
        self.main_window.show()

def main():
    return AFV()

On Windows, when you resize the window slowly, everything looks fine, But when you resize it quickly, the size of the content doesn't keep up with the size of the window:
increase
decrease

It's even worse on Android, because the layout gets stuck in its initial state where the size of the container hasn't even been calculated yet. And you can't generally force a refresh by resizing the app at will, although if the app contains a TextInput you may be able to do it by showing the keyboard.

This is happening because Widget.refresh currently calls self.refresh_sublayouts before super().refresh. So when a container is resized, its content will be laid out using the old size, not the new one:

def refresh(self):
"""Refresh the layout and appearance of the tree this node is contained in."""
if self._root:
self._root.refresh()
else:
self.refresh_sublayouts()
super().refresh(self._impl.viewport)

Reversing the order of these two lines fixes the issue, at least on Windows. However, I see that they have already been reversed by #814 (commits), with the message:

refresh_sublayouts before we refresh ourself
this fixes when adding children to widget which is the content of another (e.g. ScrollWidget) where the content dimensions would not be updated before the containing widget is refreshed

@samschott: Can you remember what this means? Why would you want the content dimensions to be refreshed before the containing widget, when the size constraints flow in the opposite direction?

Environment:

  • Operating System: Windows 10 and Android API level 33, at least
  • Python version: 3.8
  • Software versions:
    • Briefcase: 7ccc5b59
    • Toga: 6379ab8
@mhsmith mhsmith added the bug A crash or error in behavior. label Oct 18, 2022
@mhsmith
Copy link
Member Author

mhsmith commented Oct 18, 2022

Reversing the order of these two lines fixes the issue on Windows, but not on Android. This may be because changes to the size of an Android widget aren't visible in its getWidth and getHeight methods until after the next layout pass is complete. In which case, we might need to attach an OnGlobalLayoutListener to each AndroidViewport, which refreshes the content's layout as soon as the container's size change has taken effect.

@mhsmith mhsmith added windows The issue relates to Microsoft Windows support. android The issue relates to Android mobile support. labels Oct 18, 2022
@mhsmith
Copy link
Member Author

mhsmith commented Jul 10, 2023

#1628 fixed this on Android, but it's still outstanding on Windows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
android The issue relates to Android mobile support. bug A crash or error in behavior. windows The issue relates to Microsoft Windows support.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant