You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An especially difficult challenge in UI toolkits is sparse scrolling, where there is the illusion of a very large number of child widgets in the scroll area, but in reality only a small subset of the widgets outside the visible viewport are materialized. I am hopeful that the tight coupling between view and associated widget, as well as a lazy callback-driven creation of widgets, will help with this, but again, we won’t know for sure until it’s built.
This is something I've implemented, and with great performance, but it's complicated and has several challenges. A few things which occur to me...
Data list, key
Input data must be some type of list indexed by some type of key. It might be tempting just to use &mut [Item], but:
This does not work well with filters (API would require creating a Vec of filtered items).
This doesn't support generating items on demand from the key, or look-ups from an external database.
It is useful to be able to filter a view without affecting keys. The current solution in KAS is essentially that the data model may create an iterator over keys, and supports retrieving a single element via key.
Stable Id as a path
It can be desirable to give children a stable Id even when scrolled out-of-view and back. It may also be useful to support resolving an Id even when the target is not currently in-view. This is possible...
The parent (container) has an Id.
As noted above, each child item should have a Key (stable even when using only a sub-set of items aka a filter). The Key type may be known only to this container, thus the container may need to map it to an index (or sequence of indices).
Putting these together, we have a path which is stable (reproducible for items when removed from the view). This path can be resolved to a child data item even when its widget is not realised.
So, use the path as an Id? This isn't as crazy as it sounds: so long as each "child index" is small (not some random or globally unique integer) the path will compress well. This implementation stores up to 14 indices in a single u64 representation, reverting to a ref-counted heap-allocated Box<[usize]> when necessary (almost never for most UIs). The main catch is that it is not Copy.
Edit: rewrote this section
Maintaining focus when scrolling out-of-view
Druid and Xilem track navigation focus internally (within widget/pod data). Problem: if scrolling something out-of-view such that the widget is dropped, the focus is dropped. Workarounds:
Maintain many more widgets than required by the visible display to allow scrolling a limited distance without losing focus
Maintain widget repr if it has focus (may not be practical)
Track focus externally. For focus alone this is easy (it's just a path), but this is not a complete solution (e.g. is text selection also tracked externally?).
Edit: rewrote this section
Item views
A method is required to build a view from a data item; ideally something like FnMut(&Key, &mut Item) -> V.
Scrolling
Not just a draw offset
Scrolling and resizing may require new data be loaded. Since data is provided by the view not the widget the easiest solution is probably to request a repaint (construct a new view tree). The good news is that this won't be necessary on every small motion.
Tab navigation
Issue: pressing Tab (or Down etc.) may cause focus to move to a new child which has not been loaded yet. Hacky solutions:
Load new widgets in the key handling logic (but this conflicts with Xilem's clean separation of View and Widget)
Ensure the next/previous child is always loaded (even where this may be at the other end of the list). Difficult because there are quite a few possible "next" targets; over a 2D model this may wrap to the next line and keys like Tab/Down/Right/PageDown/End may all resolve different targets.
Scroll, construct a new view tree, and try again
This particular issue is a pain in KAS (where the first solution is possible); I suspect it will be difficult to get right in Xilem.
The text was updated successfully, but these errors were encountered:
From the blog post:
This is something I've implemented, and with great performance, but it's complicated and has several challenges. A few things which occur to me...
Data list, key
Input data must be some type of list indexed by some type of key. It might be tempting just to use
&mut [Item]
, but:Vec
of filtered items).It is useful to be able to filter a view without affecting keys. The current solution in KAS is essentially that the data model may create an iterator over keys, and supports retrieving a single element via key.
Stable Id as a path
It can be desirable to give children a stable
Id
even when scrolled out-of-view and back. It may also be useful to support resolving anId
even when the target is not currently in-view. This is possible...Id
.Key
(stable even when using only a sub-set of items aka a filter). TheKey
type may be known only to this container, thus the container may need to map it to an index (or sequence of indices).Putting these together, we have a path which is stable (reproducible for items when removed from the view). This path can be resolved to a child data item even when its widget is not realised.
So, use the path as an
Id
? This isn't as crazy as it sounds: so long as each "child index" is small (not some random or globally unique integer) the path will compress well. This implementation stores up to 14 indices in a singleu64
representation, reverting to a ref-counted heap-allocatedBox<[usize]>
when necessary (almost never for most UIs). The main catch is that it is notCopy
.Edit: rewrote this section
Maintaining focus when scrolling out-of-view
Druid and Xilem track navigation focus internally (within widget/pod data). Problem: if scrolling something out-of-view such that the widget is dropped, the focus is dropped. Workarounds:
Edit: rewrote this section
Item views
A method is required to build a view from a data item; ideally something like
FnMut(&Key, &mut Item) -> V
.Scrolling
Not just a draw offset
Scrolling and resizing may require new data be loaded. Since data is provided by the view not the widget the easiest solution is probably to request a repaint (construct a new view tree). The good news is that this won't be necessary on every small motion.
Tab navigation
Issue: pressing Tab (or Down etc.) may cause focus to move to a new child which has not been loaded yet. Hacky solutions:
This particular issue is a pain in KAS (where the first solution is possible); I suspect it will be difficult to get right in Xilem.
The text was updated successfully, but these errors were encountered: