{-# 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