File: TabularListDemo.hs

package info (click to toggle)
haskell-brick 2.1.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,328 kB
  • sloc: haskell: 8,492; makefile: 5
file content (146 lines) | stat: -rw-r--r-- 4,181 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE CPP #-}
module Main where

import Lens.Micro ((^.))
import Lens.Micro.Mtl
import Lens.Micro.TH
import Control.Monad (void)
#if !(MIN_VERSION_base(4,11,0))
import Data.Monoid
#endif
import qualified Graphics.Vty as V

import qualified Brick.Main as M
import qualified Brick.Types as T
import qualified Brick.Widgets.Border as B
import qualified Brick.Widgets.List as L
import qualified Brick.Widgets.Center as C
import qualified Brick.Widgets.Table as Table
import qualified Brick.AttrMap as A
import qualified Data.Vector as Vec
import Brick.Types
  ( Widget
  )
import Brick.Widgets.Core
  ( (<=>)
  , str
  , vLimit
  , hLimit
  , vBox
  , hBox
  , withDefAttr
  )
import Brick.Util (on)

data Row = Row String String String

data AppState =
    AppState { _tabularList :: L.List () Row
             , _colIndex :: Int
             }

makeLenses ''AppState

drawUI :: AppState -> [Widget ()]
drawUI s = [ui]
    where
        l = s^.tabularList
        label = str $ "Row " <> cur <> " / col " <> show (s^.colIndex + 1)
        cur = case l^.(L.listSelectedL) of
                Nothing -> "-"
                Just i -> show (i + 1)
        box = B.borderWithLabel label $
              hLimit totalWidth $
              vLimit 15 $
              listDrawElement 0 False headerRow <=>
              L.renderList (listDrawElement (s^.colIndex)) True l
        ui = C.vCenter $ vBox [ C.hCenter box
                              , str " "
                              , C.hCenter $ str "Press +/- to add/remove list elements."
                              , C.hCenter $ str "Use arrow keys to change selection."
                              , C.hCenter $ str "Press Esc to exit."
                              ]

appEvent :: T.BrickEvent () e -> T.EventM () AppState ()
appEvent (T.VtyEvent e) =
    case e of
        V.EvKey (V.KChar '+') [] -> do
            els <- use (tabularList.L.listElementsL)
            let el = Row (show pos) (show $ pos * 3) (show $ pos * 9)
                pos = Vec.length els
            tabularList %= L.listInsert pos el

        V.EvKey (V.KChar '-') [] -> do
            sel <- use (tabularList.L.listSelectedL)
            case sel of
                Nothing -> return ()
                Just i -> tabularList %= L.listRemove i

        V.EvKey V.KLeft [] ->
            colIndex %= (\i -> max 0 (i - 1))
        V.EvKey V.KRight [] ->
            colIndex %= (\i -> min (length columnAlignments - 1) (i + 1))

        V.EvKey V.KEsc [] -> M.halt

        ev -> T.zoom tabularList $ L.handleListEvent ev
appEvent _ = return ()

listDrawElement :: Int -> Bool -> Row -> Widget ()
listDrawElement colIdx sel (Row a b c) =
    let ws = [str a, str b, str c]
        maybeSelect es = selectCell <$> zip [0..] es
        selectCell (i, w) = if sel && i == colIdx
                            then withDefAttr selectedCellAttr w
                            else w
    in hLimit totalWidth $
       hBox $
       maybeSelect $
       Table.alignColumns columnAlignments columnWidths ws

initialState :: AppState
initialState =
    AppState { _tabularList = L.list () (Vec.fromList initialRows) 1
             , _colIndex = 0
             }

selectedCellAttr :: A.AttrName
selectedCellAttr = A.attrName "selectedCell"

theMap :: A.AttrMap
theMap = A.attrMap V.defAttr
    [ (L.listAttr,            V.white `on` V.blue)
    , (selectedCellAttr,      V.blue `on` V.white)
    ]

columnWidths :: [Int]
columnWidths = [10, 15, 20]

totalWidth :: Int
totalWidth = sum columnWidths

headerRow :: Row
headerRow = Row "Col 1" "Col 2" "Col 3"

columnAlignments :: [Table.ColumnAlignment]
columnAlignments = [Table.AlignLeft, Table.AlignCenter, Table.AlignRight]

initialRows :: [Row]
initialRows =
    [ Row "one" "two" "three"
    , Row "foo" "bar" "baz"
    , Row "stuff" "things" "blah"
    ]

theApp :: M.App AppState e ()
theApp =
    M.App { M.appDraw = drawUI
          , M.appChooseCursor = M.showFirstCursor
          , M.appHandleEvent = appEvent
          , M.appStartEvent = return ()
          , M.appAttrMap = const theMap
          }

main :: IO ()
main = void $ M.defaultMain theApp initialState