brick/programs/FormDemo.hs

163 lines
5.2 KiB
Haskell
Raw Normal View History

{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import qualified Data.Text as T
import Lens.Micro ((^.))
import Lens.Micro.TH
#if !(MIN_VERSION_base(4,11,0))
2017-12-27 08:56:10 +03:00
import Data.Monoid ((<>))
#endif
2017-12-27 09:32:01 +03:00
import qualified Graphics.Vty as V
2017-12-27 03:40:55 +03:00
import Brick
import Brick.Forms
2017-12-28 03:32:13 +03:00
( Form
, newForm
, formState
, formFocus
, setFieldValid
2017-12-28 03:32:13 +03:00
, renderForm
, handleFormEvent
, invalidFields
, allFieldsValid
, focusedFormInputAttr
, invalidFormInputAttr
, checkboxField
, radioField
, editShowableField
, editTextField
, editPasswordField
, (@@=)
)
2017-12-27 03:40:55 +03:00
import Brick.Focus
2017-12-28 03:32:13 +03:00
( focusGetCurrent
, focusRingCursor
)
import qualified Brick.Widgets.Edit as E
import qualified Brick.Widgets.Border as B
import qualified Brick.Widgets.Center as C
2017-12-27 08:31:18 +03:00
data Name = NameField
| AgeField
| BikeField
| HandedField
| PasswordField
| LeftHandField
| RightHandField
| AmbiField
2017-12-27 22:37:26 +03:00
| AddressField
deriving (Eq, Ord, Show)
2017-12-27 08:31:18 +03:00
data Handedness = LeftHanded | RightHanded | Ambidextrous
deriving (Show, Eq)
2017-12-28 02:37:51 +03:00
data UserInfo =
UserInfo { _name :: T.Text
, _age :: Int
, _address :: T.Text
, _ridesBike :: Bool
, _handed :: Handedness
, _password :: T.Text
}
deriving (Show)
makeLenses ''UserInfo
2017-12-28 05:34:58 +03:00
-- This form is covered in the Brick User Guide; see the "Input Forms"
-- section.
2017-12-28 02:37:51 +03:00
mkForm :: UserInfo -> Form UserInfo e Name
mkForm =
2017-12-27 08:52:26 +03:00
let label s w = padBottom (Pad 1) $
(vLimit 1 $ hLimit 15 $ str s <+> fill ' ') <+> w
in newForm [ label "Name" @@=
2017-12-27 08:39:20 +03:00
editTextField name NameField (Just 1)
2017-12-27 22:37:26 +03:00
, label "Address" @@=
2017-12-28 04:57:49 +03:00
B.borderWithLabel (str "Mailing") @@=
2017-12-27 22:37:26 +03:00
editTextField address AddressField (Just 3)
2017-12-27 08:52:26 +03:00
, label "Age" @@=
2017-12-27 08:39:20 +03:00
editShowableField age AgeField
2017-12-27 08:52:26 +03:00
, label "Password" @@=
2017-12-27 08:39:20 +03:00
editPasswordField password PasswordField
2017-12-27 08:52:26 +03:00
, label "Dominant hand" @@=
2017-12-27 08:39:20 +03:00
radioField handed [ (LeftHanded, LeftHandField, "Left")
, (RightHanded, RightHandField, "Right")
, (Ambidextrous, AmbiField, "Both")
]
2017-12-27 09:07:41 +03:00
, label "" @@=
checkboxField ridesBike BikeField "Do you ride a bicycle?"
2017-12-27 08:39:20 +03:00
]
theMap :: AttrMap
theMap = attrMap V.defAttr
[ (E.editAttr, V.white `on` V.black)
, (E.editFocusedAttr, V.black `on` V.yellow)
, (invalidFormInputAttr, V.white `on` V.red)
, (focusedFormInputAttr, V.black `on` V.yellow)
]
2017-12-28 02:37:51 +03:00
draw :: Form UserInfo e Name -> [Widget Name]
2017-12-28 03:32:13 +03:00
draw f = [C.vCenter $ C.hCenter form <=> C.hCenter help]
2017-12-27 08:52:26 +03:00
where
2017-12-28 03:32:13 +03:00
form = B.border $ padTop (Pad 1) $ hLimit 50 $ renderForm f
help = padTop (Pad 1) $ B.borderWithLabel (str "Help") body
2017-12-27 08:56:10 +03:00
body = str $ "- Name is free-form text\n" <>
"- Age must be an integer (try entering an\n" <>
" invalid age!)\n" <>
"- Handedness selects from a list of options\n" <>
2017-12-27 10:03:03 +03:00
"- The last option is a checkbox\n" <>
"- Enter/Esc quit, mouse interacts with fields"
2017-12-27 08:52:26 +03:00
2017-12-28 02:37:51 +03:00
app :: App (Form UserInfo e Name) e Name
app =
2017-12-27 08:52:26 +03:00
App { appDraw = draw
, appHandleEvent = \s ev ->
case ev of
VtyEvent (V.EvResize {}) -> continue s
VtyEvent (V.EvKey V.KEsc []) -> halt s
2017-12-27 22:37:26 +03:00
-- Enter quits only when we aren't in the multi-line editor.
VtyEvent (V.EvKey V.KEnter [])
2017-12-27 22:37:26 +03:00
| focusGetCurrent (formFocus s) /= Just AddressField -> halt s
_ -> do
s' <- handleFormEvent ev s
-- Example of external validation:
-- Require age field to contain a value that is at least 18.
continue $ setFieldValid ((formState s')^.age >= 18) AgeField s'
, appChooseCursor = focusRingCursor formFocus
, appStartEvent = return
, appAttrMap = const theMap
}
main :: IO ()
main = do
2017-12-27 09:32:01 +03:00
let buildVty = do
v <- V.mkVty =<< V.standardIOConfig
V.setMode (V.outputIface v) V.Mouse True
return v
2017-12-28 02:37:51 +03:00
initialUserInfo = UserInfo { _name = ""
, _address = ""
, _age = 0
, _handed = RightHanded
, _ridesBike = False
, _password = ""
}
f = setFieldValid False AgeField $
mkForm initialUserInfo
2017-12-27 09:32:01 +03:00
initialVty <- buildVty
f' <- customMain initialVty buildVty Nothing app f
putStrLn "The starting form state was:"
2017-12-28 02:37:51 +03:00
print initialUserInfo
putStrLn "The final form state was:"
2017-12-28 03:26:04 +03:00
print $ formState f'
if allFieldsValid f'
then putStrLn "The final form inputs were valid."
else putStrLn $ "The final form had invalid inputs: " <> show (invalidFields f')