Tui improvements
Wrt #69 (closed)
Inserting separators isn't possible with how brick processes lists? I think that would require a lot of work to feel natural with navigation. I'm considering to insert an empty row though, but that also needs some work.
Merge request reports
Activity
mentioned in issue #69 (closed)
@jtdaugherty do you have an idea on how to insert separators between different tools? Afais this isn't easily possible with how
renderList
works.I believe @glguy also had some ideas about how this could be done a bit differently that wouldn't depend on a monolithic list approach; perhaps he can comment.
The way we'd discussed in another forum was that we could have a two-level approach; first you pick a tool and then you get all that tool's versions.
The first list might look like this sketch
Tool Recommended Latest --------------------------------- ghc 8.8.4 8.10.2 hls 0.5.0 0.5.0 cabal 3.2.0.0 3.2.0.0 ghcup 0.1.11 0.1.11
We could decorate that with pretty green checkmarks next to things to indicate which were installed. The leftmost check could mean it was installed at all, and then if a recommended or latest version was installed we could indicate that too.
Tool Recommended Latest --------------------------------- ✓ ghc 8.8.4 ✓ 8.10.2 hls 0.5.0 0.5.0 ✓ cabal ✓ 3.2.0.0 ✓ 3.2.0.0 ✓ ghcup 0.1.11 0.1.11
This view makes it clear which tools are available in
ghcup
and makes it clear which tools are "outdated" with a glance.
I believe everything is working.
Edited by Julian Ospald164 164 then emptyWidget 165 165 else foldr1 (\x y -> x <+> str "," <+> y) $ notes 166 166 ) 167 <+> (vLimit 1 $ fill ' ') data ListResult = ListResult { lTool :: Tool , lVer :: Version , lCross :: Maybe Text -- ^ currently only for GHC , lTag :: [Tag] , lInstalled :: Bool , lSet :: Bool -- ^ currently active version , fromSrc :: Bool -- ^ compiled from source , lStray :: Bool -- ^ not in download info , lNoBindist :: Bool -- ^ whether the version is available for this platform/arch , hlsPowered :: Bool }
212 213 listItemHeight = 1 214 listSelected = fmap fst $ listSelectedElement' is 215 216 -- The number of items to show is the available height 217 -- divided by the item height... 218 initialNumPerHeight = (c ^. availHeightL - seps) `div` listItemHeight 219 -- ... but if the available height leaves a remainder of 220 -- an item height then we need to ensure that we render an 221 -- extra item to show a partial item at the top or bottom to 222 -- give the expected result when an item is more than one 223 -- row high. (Example: 5 rows available with item height 224 -- of 3 yields two items: one fully rendered, the other 225 -- rendered with only its top 2 or bottom 2 rows visible, 226 -- depending on how the viewport state changes.) 227 numPerHeight = This logic about
numPerHeight
andlistItemHeight
needs to go away if you need to have list items with different heights. The reason thisnumPerHeight
stuff is in here is as an optimization to avoid drawing too many items that won't be visible anyway, but you will have to abandon that optimization if your items have different heights. This also means the viewport translation usingoff
needs to be removed. The approach you're taking where you addvisible
and embed the results in aviewport
will work okay without this, but just note that it won't scale if you have hundreds of list elements because at some point there is a drawing cost for those that will introduce latency in your rendering loop.changed this line in version 3 of the diff
If some of the items contain separators, they are not the all the same height. Some are 1 row high, others are 2 high. The difference matters because the number of items to render relies on the connection between the item height and the viewport height. If they aren't the same height, that calculation will get that wrong sometimes, leading to strange scrolling behavior. You might never notice for most UI sizes, but for some viewport heights (i.e. window heights) you may run into problems once there are enough items with and without separators to trigger errors in that logic.
Yes, the
List
in the library follows approach (1). The logic cannot be fixed to account for items with different heights unless the optimization to render fewer items is removed (i.e. the logic related tonumPerHeight
). IntroducinghBorder
s for some items (i.e. making them have different heights) will ultimately break that optimization and lead to broken scrolling behavior, depending on the viewport height.So you are saying this
addSeparator w = case es !? (i' - 1) of Just e' | lTool e' /= lTool e -> hBorder <=> w _ -> w
breaks the logic and I have to make the separator an actual item for the input list instead of composing it with a row? Something like
[Either (Widget String) ListResult]
?You could make the separators list items to avoid the issue I mentioned, but I wouldn't recommend it since that will be awkward. You'd end up with separators that could be selected, and that probably isn't what you want. I'm just saying that if you want to put these separators in while also re-using the
List
implementation, you'll need to remove the code that attempts to render less than the entire list in order to avoid the scrolling issues that will come up. All this amounts to in the end is that you'll haverender $ viewport "GHCup" Vertical $ vBox $ V.toList drawnElements
instead of
render $ viewport "GHCup" Vertical $ translateBy (Location (0, off)) $ vBox $ V.toList drawnElements
and then the binding to
es
will bees = clr
instead of
es = slice start (numPerHeight * 2) clr