Fix/progess spinner resizing
Fixes https://github.com/stackotter/swift-cross-ui/issues/237
Visually Breaking Change for some existing UIs using ProgressSpinner
This PR makes ProgressSpinners resizable on supported backends. Unsupported Backends change the container size without changing how the Widgets is actually being rendered to the user.
All changes are SCUI-Level, so even Backends I didn’t test (Gtk3) should benefit from it without breaking.
It may break some existing UIs though, as it now can be squished smaller than its natural size. To make it not entirely disappear (without setting a frame manually) I set its width/height to a minimum of 10 points, it can‘t shrink smaller.
To determine its rendered size it takes the smaller axis length and applies it to both width and height (making sure it always fits inside the applied constraints).
This can lead to it being rendered smaller than a set frame, if only one axis is set and its being squished from the opposite site. setting both axes in .frame eliminates this „problem“.
Gtk seems to have a min size for its Spinner. This can lead to clipping on too small externally applied constraints (at least on Ubuntu). I don’t really consider this to be an issue though as it can easily be avoided by the developer and other views can clip too.
My concern with resizable spinners is that I'll often do something like
HStack {
Spacer()
ProgressView()
Spacer()
}
to center a spinner within a larger view. Would this lead to a ridiculously large spinner on a large enough screen?
My concern with resizable spinners is that I'll often do something like
HStack { Spacer() ProgressView() Spacer() }to center a spinner within a larger view. Would this lead to a ridiculously large spinner on a large enough screen?
Perhaps this resizability can be gated behind a .resizable() modifier similar to Image resizability?
My concern with resizable spinners is that I'll often do something like
HStack { Spacer() ProgressView() Spacer() }to center a spinner within a larger view. Would this lead to a ridiculously large spinner on a large enough screen?
Perhaps this resizability can be gated behind a
.resizable()modifier similar to Image resizability?
Exactly what I did.
I’m going to replace the function with how its done on the Image in a moment. I like it better.
It doesn't need to be done now (I could do this in a future PR), but maybe some code could be added to UIKitBackend to change the spinner between .medium and .large depending on its frame? I don't think there's an updateProgressSpinner backend method, so this would probably have to go on the widget's layoutSubviews method.
Whatever threshold we choose, we have to make sure it's large enough that the .large style is never chosen when it could be cut off on any platform (not just OS, but also based on OS version and maybe even accessibility settings. If you don't want to test it all I totally understand; I can get to it this weekend.)
maybe some code could be added to UIKitBackend to change the spinner between
.mediumand.largedepending on its frame?
totally. I decided to not do it in this pr because the scope was scui isolated and I wanted to stay it that way. (Also I wasn't sure yet how I'd like the api to look for it. Single Backend support is way harder for api design imo. Especially when its kind of overlapping with another modifier but not really.)
Maybe .style() or whatever it would be called could apply .resizable() and .frame(constant size) depending on .medium or .large? so it wouldn't be UIKit Backend specific anymore (even though the other backends wouldn't need specific code)
Here's what I've found from testing locally;
GtkBackend and Gtk3Backend
- Work perfectly.
AppKitBackend
-
Spinner animates its size kinda weirdly when switching between enabled and disabled. I think it shouldn't animate at all (to make our job easier when we add an animation system).
-
The
ControlsExamplecrashes when I use the spinner size slider. It appears to be due to a feedback loop in the window sizing code (that eventually leads to running out of stack space). The feedback loop is likely unrelated to your changes. If you can reproduce the crash locally then it'd be worth making a reproducer for it. Otherwise I can once I get the time. -
I've confirmed that the crash doesn't occur when the ControlsExample is inside a ScrollView. I think it should be in a ScrollView anyway given that it's so tall now. So feel free to pop it in a ScrollView and I'll look into the crash later.
UIKitBackend
- Works other than the behaviour you documented (that the spinner doesn't resize).
WinUIBackend
- Works perfectly.