-
-
Notifications
You must be signed in to change notification settings - Fork 685
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
[widget Audit] toga.ScrollContainer #1969
Conversation
a860811
to
e256720
Compare
5b5b21d
to
8f56f27
Compare
afb0600
to
ba3a44f
Compare
ba3a44f
to
73edde4
Compare
I've just (re)audited the ScrollContainer issues; I've presumptively put them all on the ticket as "fixed"; the current status of each AFAICT is: [Merged into the Fixes list above, except for the following. -- @mhsmith]
|
The same has now been done for Winforms and Android. |
self._content = widget | ||
self.refresh() | ||
if widget: | ||
widget.refresh() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My reasoning for this change is that setting the content should not affect the size of self
(the container), but it will affect the size of widget
(the content).
Is this correct? And if so, is there anything which might incorrectly be depending on the previous behavior?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed that this seems correct. I can't think of any behavior that would depending on this - it's just an easy optimisation, AFAICT.
On Cocoa/iOS, calling refresh on the widget will cause set_bounds()
to be invoked on the widget, which will trigger a refresh on the content anyway; this optimisation shortcuts the unnecessary changes to the container, and goes directly to the content. When the content layout completes (or any other content change is applied), the container scroll bounds are updated by the on_refresh
callback on the container.
On GTK, all you're changing is which widget is marked as dirty; once the widget is marked as dirty, it will get a layout in the next render pass. Again, all this change does is optimise how much is marked as dirty.
Winforms is now passing the testbed, but I still need to verify that everything in the Fixes list above is actually fixed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of questions inline; the only big issue I see is the composition vs inheritance thing for Window and ScrollContainer. Inheritance clearly works for these two cases - although the approach won't work for OptionContainer and SplitContainer (because there's multiple sub-containers).
def viewport(self): | ||
return self._container | ||
|
||
def scale_in(self, value): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A quick note for future explorers on which direction is "in" and "out" would be helpful here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, done.
|
||
|
||
class Window: | ||
class Window(Container): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a particular reason for using "is-A" rather than "has-A" as the composition for Window and Container? It's an interesting discrepancy between the iOS/Cocoa/GTK world and the Android one; I'm wondering what the source of that difference is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree the benefit of inheritance turned out to be fairly small. It's mainly just providing a single implementation of the set_content
method, reducing the number of distinct objects you need to keep track of, and unifying the meaning of the word "container".
As discussed, my preference is to keep it the way it is for this PR, and revisit it in the SplitContainer PR where the container/content relationship will no longer be 1-1.
return self._viewport | ||
return self._container | ||
|
||
def scale_in(self, value): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As with android - some documentation for future explorers would be helpful
|
||
class ScrollContainer(Widget, Container): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar thing here with composition vs inheritance for the ScrollContainer.
# at the top of this file). | ||
def apply_insets(): | ||
need_scrollbar = False | ||
if self.vertical and layout.height > self.height: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this comparison be with self.height, or inset_height?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.height
is the correct value in both cases:
- In the first call to
apply_insets
,self.height == full_height
, because you're checking whether the initial layout needs a vertical scroll bar. - In the second call,
self.height
may have been set toinset_height
if a horizontal scroll bar was added by the first call, in which case we now need to check whether the second layout fits in that smaller space.
vertical_shift += self.native.MainMenuStrip.Height | ||
|
||
self.native_content.Location = Point(0, vertical_shift) | ||
super().resize_content( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the essentially the reason I'm questioning the composition vs inheritance approach - composition gives a clear distinction between the process of resizing the window, and the fact this requires resizing the container.
Confirmed that all the Windows issues in the Fixes list are actually fixed, except for #1606, which I've added some notes to. |
Everything looks fine now, except for a couple of uncovered branches in Cocoa and iOS which I'm not sure how to fix:
|
Testbed test case added for the 2 missing lines. It's the edge case of a ScrollContainer with no content having it's layout updated. Looks like GTK, Windows, and Android all pass that test case without any additional changes. |
Audit of ScrollContainer.
Includes a Cocoa and iOS version of #1794. This allows us to remove the special case handling of the root content object in any given layout - constraints are used for all Toga widgets, rather than "all widgets except the root widget", and we now know that all widgets that are in a layout have a container.
It also fixes some issues with ScrollContainer specifically, as we need to decouple the size of the document being scrolled from the layout:
Some changes that follow on from this:
refresh_sublayouts
isn't needed for scroll container; and I suspect it won't be needed for OptionContainer or SplitContainer either.Issues fixed:
Audit checklist