module EVM.TTYCenteredList where

-- Hard fork of brick's List that centers the currently highlighted line.

import Optics.Core
import Data.Maybe (fromMaybe)

import Brick.Types
import Brick.Widgets.Core
import Brick.Widgets.List

import qualified Data.Vector as V

-- | Turn a list state value into a widget given an item drawing
-- function.
renderList :: (Ord n, Show n)
           => (Bool -> e -> Widget n)
           -- ^ Rendering function, True for the selected element
           -> Bool
           -- ^ Whether the list has focus
           -> List n e
           -- ^ The List to be rendered
           -> Widget n
           -- ^ rendered widget
renderList :: forall n e.
(Ord n, Show n) =>
(Bool -> e -> Widget n) -> Bool -> List n e -> Widget n
renderList Bool -> e -> Widget n
drawElem Bool
foc List n e
l =
    forall n. AttrName -> Widget n -> Widget n
withDefAttr AttrName
listAttr forall a b. (a -> b) -> a -> b
$
    forall n e.
(Ord n, Show n) =>
Bool -> List n e -> (Bool -> e -> Widget n) -> Widget n
drawListElements Bool
foc List n e
l Bool -> e -> Widget n
drawElem

drawListElements :: (Ord n, Show n) => Bool -> List n e -> (Bool -> e -> Widget n) -> Widget n
drawListElements :: forall n e.
(Ord n, Show n) =>
Bool -> List n e -> (Bool -> e -> Widget n) -> Widget n
drawListElements Bool
foc List n e
l Bool -> e -> Widget n
drawElem =
    forall n. Size -> Size -> RenderM n (Result n) -> Widget n
Widget Size
Greedy Size
Greedy forall a b. (a -> b) -> a -> b
$ do
        Context n
c <- forall n. RenderM n (Context n)
getContext

        let es :: Vector e
es = forall a. Int -> Int -> Vector a -> Vector a
V.slice Int
start Int
num (List n e
l forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. (forall s t a b. LensVL s t a b -> Lens s t a b
lensVL forall n (t1 :: * -> *) e1 (t2 :: * -> *) e2.
Lens (GenericList n t1 e1) (GenericList n t2 e2) (t1 e1) (t2 e2)
listElementsL))
            idx :: Int
idx = forall a. a -> Maybe a -> a
fromMaybe Int
0 (List n e
l forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. (forall s t a b. LensVL s t a b -> Lens s t a b
lensVL forall n (t :: * -> *) e. Lens' (GenericList n t e) (Maybe Int)
listSelectedL))

            start :: Int
start = forall a. Ord a => a -> a -> a
max Int
0 forall a b. (a -> b) -> a -> b
$ Int
idx forall a. Num a => a -> a -> a
- (Int
initialNumPerHeight forall a. Integral a => a -> a -> a
`div` Int
2)
            num :: Int
num = forall a. Ord a => a -> a -> a
min (Int
numPerHeight forall a. Num a => a -> a -> a
* Int
2) (forall a. Vector a -> Int
V.length (List n e
l forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. (forall s t a b. LensVL s t a b -> Lens s t a b
lensVL forall n (t1 :: * -> *) e1 (t2 :: * -> *) e2.
Lens (GenericList n t1 e1) (GenericList n t2 e2) (t1 e1) (t2 e2)
listElementsL)) forall a. Num a => a -> a -> a
- Int
start)

            -- The number of items to show is the available height divided by
            -- the item height...
            initialNumPerHeight :: Int
initialNumPerHeight = (Context n
c forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. (forall s t a b. LensVL s t a b -> Lens s t a b
lensVL forall n. Lens' (Context n) Int
availHeightL)) forall a. Integral a => a -> a -> a
`div` (List n e
l forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. (forall s t a b. LensVL s t a b -> Lens s t a b
lensVL forall n (t :: * -> *) e. Lens' (GenericList n t e) Int
listItemHeightL))
            -- ... but if the available height leaves a remainder of
            -- an item height then we need to ensure that we render an
            -- extra item to show a partial item at the top or bottom to
            -- give the expected result when an item is more than one
            -- row high. (Example: 5 rows available with item height
            -- of 3 yields two items: one fully rendered, the other
            -- rendered with only its top 2 or bottom 2 rows visible,
            -- depending on how the viewport state changes.)
            numPerHeight :: Int
numPerHeight = Int
initialNumPerHeight forall a. Num a => a -> a -> a
+
                           if Int
initialNumPerHeight forall a. Num a => a -> a -> a
* (List n e
l forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. (forall s t a b. LensVL s t a b -> Lens s t a b
lensVL forall n (t :: * -> *) e. Lens' (GenericList n t e) Int
listItemHeightL)) forall a. Eq a => a -> a -> Bool
== Context n
c forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. (forall s t a b. LensVL s t a b -> Lens s t a b
lensVL forall n. Lens' (Context n) Int
availHeightL)
                           then Int
0
                           else Int
1

            -- off = start * (l^.listItemHeightL)

            drawnElements :: Vector (Widget n)
drawnElements = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. (Int -> a -> b) -> Vector a -> Vector b
V.imap Vector e
es forall a b. (a -> b) -> a -> b
$ \Int
i e
e ->
                let isSelected :: Bool
isSelected = Int
i forall a. Eq a => a -> a -> Bool
== (if Int
start forall a. Eq a => a -> a -> Bool
== Int
0 then Int
idx else forall a. Integral a => a -> a -> a
div Int
initialNumPerHeight Int
2)
                    elemWidget :: Widget n
elemWidget = Bool -> e -> Widget n
drawElem Bool
isSelected e
e
                    selItemAttr :: Widget n -> Widget n
selItemAttr = if Bool
foc
                                  then forall n. AttrName -> Widget n -> Widget n
withDefAttr AttrName
listSelectedFocusedAttr
                                  else forall n. AttrName -> Widget n -> Widget n
withDefAttr AttrName
listSelectedAttr
                    makeVisible :: Widget n -> Widget n
makeVisible = if Bool
isSelected
                                  then forall n. Widget n -> Widget n
visible forall b c a. (b -> c) -> (a -> b) -> a -> c
. Widget n -> Widget n
selItemAttr
                                  else forall a. a -> a
id
                in Widget n -> Widget n
makeVisible Widget n
elemWidget

        forall n. Widget n -> RenderM n (Result n)
render forall a b. (a -> b) -> a -> b
$ forall n.
(Ord n, Show n) =>
n -> ViewportType -> Widget n -> Widget n
viewport (List n e
l forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. (forall s t a b. LensVL s t a b -> Lens s t a b
lensVL forall n1 (t :: * -> *) e n2.
Lens (GenericList n1 t e) (GenericList n2 t e) n1 n2
listNameL)) ViewportType
Vertical forall a b. (a -> b) -> a -> b
$
                 -- translateBy (Location (0, off)) $
                 forall n. [Widget n] -> Widget n
vBox forall a b. (a -> b) -> a -> b
$ forall a. Vector a -> [a]
V.toList Vector (Widget n)
drawnElements