ui: refactor, generalise listScrollPushingSelection

This commit is contained in:
Simon Michael 2021-11-18 07:53:02 -10:00
parent 731a416b8c
commit 9f6595f122
3 changed files with 36 additions and 61 deletions

View File

@ -13,11 +13,10 @@ where
import Brick import Brick
import Brick.Widgets.List import Brick.Widgets.List
(handleListEvent, list, listElementsL, listMoveDown, listMoveTo, listNameL, listSelectedElement, listSelectedL, renderList, listElements, listSelected, listMoveUp)
import Brick.Widgets.Edit import Brick.Widgets.Edit
import Control.Monad import Control.Monad
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Data.List import Data.List hiding (reverse)
import Data.Maybe import Data.Maybe
import qualified Data.Text as T import qualified Data.Text as T
import Data.Time.Calendar (Day) import Data.Time.Calendar (Day)
@ -339,36 +338,12 @@ asHandle ui0@UIState{
vScrollBy (viewportScroll $ _asList^.listNameL) 1 >> continue ui vScrollBy (viewportScroll $ _asList^.listNameL) 1 >> continue ui
where mnextelement = listSelectedElement $ listMoveDown _asList where mnextelement = listSelectedElement $ listMoveDown _asList
-- mouse scroll wheel scrolls the viewport up or down to its maximum extent. -- mouse scroll wheel scrolls the viewport up or down to its maximum extent,
-- The selection will be moved when necessary to keep it visible and allow the scroll. -- pushing the selection when necessary.
MouseDown name BScrollDown _mods _loc -> do MouseDown name btn _mods _loc | btn `elem` [BScrollUp, BScrollDown] -> do
mvp <- lookupViewport name let scrollamt = if btn==BScrollUp then -1 else 1
let mselidx = listSelected _asList list' <- listScrollPushingSelection name _asList (asListSize _asList) scrollamt
case (mvp, mselidx) of continue ui{aScreen=scr{_asList=list'}}
(Just VP{_vpTop}, Just selidx) -> do
let
listheight = asListSize _asList
pushsel | selidx <= _vpTop && selidx < (listheight-1) = listMoveDown
| otherwise = id
ui' = ui{aScreen=scr{_asList=pushsel _asList}}
viewportScroll name `vScrollBy` 1
continue ui'
_ -> continue ui
MouseDown name BScrollUp _mods _loc -> do
mvp <- lookupViewport name
let mselidx = listSelected _asList
case (mvp, mselidx) of
(Just VP{_vpTop, _vpSize=(_,vpheight)}, Just selidx) -> do
let
pushsel | selidx >= _vpTop + vpheight - 1 && selidx > 0 = listMoveUp
| otherwise = id
ui' = ui{aScreen=scr{_asList=pushsel _asList}}
viewportScroll name `vScrollBy` (-1)
continue ui'
_ -> continue ui
-- if page down or end leads to a blank padding item, stop at last non-blank -- if page down or end leads to a blank padding item, stop at last non-blank
VtyEvent e@(EvKey k []) | k `elem` [KPageDown, KEnd] -> do VtyEvent e@(EvKey k []) | k `elem` [KPageDown, KEnd] -> do

View File

@ -22,8 +22,7 @@ import Data.Time.Calendar
import qualified Data.Vector as V import qualified Data.Vector as V
import Graphics.Vty (Event(..),Key(..),Modifier(..), Button (BLeft, BScrollDown, BScrollUp)) import Graphics.Vty (Event(..),Key(..),Modifier(..), Button (BLeft, BScrollDown, BScrollUp))
import Brick import Brick
import Brick.Widgets.List import Brick.Widgets.List hiding (reverse)
(handleListEvent, list, listElementsL, listMoveDown, listMoveTo, listNameL, listSelectedElement, listSelectedL, renderList, listElements, listSelected, listMoveUp)
import Brick.Widgets.Edit import Brick.Widgets.Edit
import Lens.Micro.Platform import Lens.Micro.Platform
import Safe import Safe
@ -379,31 +378,11 @@ rsHandle ui@UIState{
where mnextelement = listSelectedElement $ listMoveDown rsList where mnextelement = listSelectedElement $ listMoveDown rsList
-- mouse scroll wheel scrolls the viewport up or down to its maximum extent, -- mouse scroll wheel scrolls the viewport up or down to its maximum extent,
-- The selection will be moved when necessary to keep it visible and allow the scroll. -- pushing the selection when necessary.
MouseDown name BScrollDown _mods _loc -> do MouseDown name btn _mods _loc | btn `elem` [BScrollUp, BScrollDown] -> do
mvp <- lookupViewport name let scrollamt = if btn==BScrollUp then -1 else 1
let mselidx = listSelected rsList list' <- listScrollPushingSelection name rsList (rsListSize rsList) scrollamt
case (mvp, mselidx) of continue ui{aScreen=s{rsList=list'}}
(Just VP{_vpTop}, Just selidx) -> do
let
pushsel | selidx <= _vpTop && selidx < (listheight-1) = listMoveDown
| otherwise = id
where listheight = rsListSize rsList
viewportScroll name `vScrollBy` 1
continue ui{aScreen=s{rsList=pushsel rsList}}
_ -> continue ui
MouseDown name BScrollUp _mods _loc -> do
mvp <- lookupViewport name
let mselidx = listSelected rsList
case (mvp, mselidx) of
(Just VP{_vpTop, _vpSize=(_,vpheight)}, Just selidx) -> do
let
pushsel | selidx >= _vpTop + vpheight - 1 && selidx > 0 = listMoveUp
| otherwise = id
viewportScroll name `vScrollBy` (-1)
continue ui{aScreen=s{rsList=pushsel rsList}}
_ -> continue ui
-- if page down or end leads to a blank padding item, stop at last non-blank -- if page down or end leads to a blank padding item, stop at last non-blank
VtyEvent e@(EvKey k []) | k `elem` [KPageDown, KEnd] -> do VtyEvent e@(EvKey k []) | k `elem` [KPageDown, KEnd] -> do

View File

@ -2,6 +2,7 @@
{-# LANGUAGE CPP #-} {-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NamedFieldPuns #-}
module Hledger.UI.UIUtils ( module Hledger.UI.UIUtils (
borderDepthStr borderDepthStr
@ -25,7 +26,8 @@ module Hledger.UI.UIUtils (
,suspend ,suspend
,redraw ,redraw
,reportSpecSetFutureAndForecast ,reportSpecSetFutureAndForecast
) ,listScrollPushingSelection
)
where where
import Brick import Brick
@ -33,7 +35,7 @@ import Brick.Widgets.Border
import Brick.Widgets.Border.Style import Brick.Widgets.Border.Style
import Brick.Widgets.Dialog import Brick.Widgets.Dialog
import Brick.Widgets.Edit import Brick.Widgets.Edit
import Brick.Widgets.List (List, listSelectedL, listNameL, listItemHeightL) import Brick.Widgets.List (List, listSelectedL, listNameL, listItemHeightL, listSelected, listMoveDown, listMoveUp, GenericList, Splittable)
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Data.Bifunctor (second) import Data.Bifunctor (second)
import Data.List import Data.List
@ -360,3 +362,22 @@ reportSpecSetFutureAndForecast d forecast rspec =
Not (Date $ DateSpan (Just $ addDays 1 d) Nothing) Not (Date $ DateSpan (Just $ addDays 1 d) Nothing)
,Not generatedTransactionTag ,Not generatedTransactionTag
] ]
-- Vertically scroll the named list with the given number of non-empty items
-- by the given positive or negative number of items (usually 1 or -1).
-- The selection will be moved when necessary to keep it visible and allow the scroll.
listScrollPushingSelection :: (Ord n, Foldable t, Splittable t) =>
n -> GenericList n t e -> Int -> Int -> EventM n (GenericList n t e)
listScrollPushingSelection name list listheight scrollamt = do
mvp <- lookupViewport name
let mselidx = listSelected list
case (mvp, mselidx) of
(Just VP{_vpTop, _vpSize=(_,vpheight)}, Just selidx) -> do
viewportScroll name `vScrollBy` scrollamt
return $ pushsel list
where
pushsel
| scrollamt > 0, selidx <= _vpTop && selidx < (listheight-1) = listMoveDown
| scrollamt < 0, selidx >= _vpTop + vpheight - 1 && selidx > 0 = listMoveUp
| otherwise = id
_ -> return list