{-# LANGUAGE Rank2Types #-}
module Summoner.Tui.Field
( strField
, checkboxField
, activeCheckboxField
, radioField
, disabledAttr
) where
import Brick (BrickEvent (..), EventM, Location (..), Widget, clickable, showCursor, str, vBox,
withAttr, withDefAttr, (<+>))
import Brick.AttrMap (AttrName)
import Brick.Forms (FormField (..), FormFieldState (..), checkboxCustomField, focusedFormInputAttr,
radioCustomField)
import Lens.Micro (Lens', lens, (^.))
import qualified Graphics.Vty as V
strField :: forall s e n . String -> s -> FormFieldState s e n
strField t _ = FormFieldState
{ formFieldState = ()
, formFieldLens = fakeLens
, formFields = []
, formFieldRenderHelper = renderString
, formFieldConcat = vBox
}
where
fakeLens :: Lens' s ()
fakeLens = lens (const ()) (\s () -> s)
renderString :: Widget n -> Widget n
renderString w = str t <+> w
checkboxField
:: (Ord n, Show n)
=> Lens' s Bool
-> n
-> Text
-> s
-> FormFieldState s e n
checkboxField = checkboxCustomField '⟦' '✔' '⟧'
radioField
:: (Ord n, Show n, Eq a)
=> Lens' s a
-> [(a, n, Text)]
-> s
-> FormFieldState s e n
radioField = radioCustomField '❮' '◆' '❯'
activeCheckboxField
:: forall n s e . Ord n
=> Lens' s Bool
-> (s -> n -> Bool)
-> n
-> String
-> s
-> FormFieldState s e n
activeCheckboxField stLens isActive name label initialState = FormFieldState
{ formFieldState = initVal
, formFields = [checkboxFormField]
, formFieldLens = stLens
, formFieldRenderHelper = id
, formFieldConcat = vBox
}
where
initVal, isEnabled :: Bool
initVal = initialState ^. stLens
isEnabled = isActive initialState name
handleEvent :: BrickEvent n e -> Bool -> EventM n Bool
handleEvent (MouseDown n _ _ _)
| isEnabled && n == name = pure . not
handleEvent (VtyEvent (V.EvKey (V.KChar ' ') [])) = pure . not
handleEvent _ = pure
checkboxFormField :: FormField Bool Bool e n
checkboxFormField = FormField
{ formFieldName = name
, formFieldValidate = Just
, formFieldExternallyValid = True
, formFieldRender = renderCheckbox isEnabled label name
, formFieldHandleEvent = handleEvent
}
renderCheckbox :: Bool -> String -> n -> Bool -> Bool -> Widget n
renderCheckbox isEnabled label n foc val =
let addAttr = if foc then withDefAttr focusedFormInputAttr else id
csr = if foc then showCursor n (Location (1,0)) else id
in if isEnabled
then clickable n $ addAttr $ csr $ str $
"⟦" <> (if val then "✔" else " ") <> "⟧" <> " " <> label
else withAttr disabledAttr $ str $ "⟦ ⟧ " <> label
disabledAttr :: AttrName
disabledAttr = "disabled"