{-# LANGUAGE CPP #-} {-# LANGUAGE TemplateHaskell #-} module Main where import Lens.Micro ((^.)) import Lens.Micro.TH (makeLenses) import Lens.Micro.Mtl import Control.Monad (void) import Control.Monad.Trans (liftIO) #if !(MIN_VERSION_base(4,11,0)) import Data.Monoid ((<>)) #endif import qualified Graphics.Vty as V import qualified Brick.Types as T import Brick.AttrMap import Brick.Util import Brick.Types (Widget, ViewportType(Vertical)) import qualified Brick.Main as M import qualified Brick.Widgets.Edit as E import qualified Brick.Widgets.Center as C import qualified Brick.Widgets.Border as B import Brick.Widgets.Core data Name = Info | Button1 | Button2 | Button3 | Prose | TextBox deriving (Show, Ord, Eq) data St = St { _clicked :: [T.Extent Name] , _lastReportedClick :: Maybe (Name, T.Location) , _prose :: String , _edit :: E.Editor String Name } makeLenses ''St drawUi :: St -> [Widget Name] drawUi st = [ buttonLayer st , proseLayer st , infoLayer st ] buttonLayer :: St -> Widget Name buttonLayer st = C.vCenterLayer $ C.hCenterLayer (padBottom (Pad 1) $ str "Click a button:") <=> C.hCenterLayer (hBox $ padLeftRight 1 <$> buttons) <=> C.hCenterLayer (padTopBottom 1 $ str "Or enter text and then click in this editor:") <=> C.hCenterLayer (vLimit 3 $ hLimit 50 $ E.renderEditor (str . unlines) True (st^.edit)) where buttons = mkButton <$> buttonData buttonData = [ (Button1, "Button 1", attrName "button1") , (Button2, "Button 2", attrName "button2") , (Button3, "Button 3", attrName "button3") ] mkButton (name, label, attr) = let wasClicked = (fst <$> st^.lastReportedClick) == Just name in clickable name $ withDefAttr attr $ B.border $ padTopBottom 1 $ padLeftRight (if wasClicked then 2 else 3) $ str (if wasClicked then "<" <> label <> ">" else label) proseLayer :: St -> Widget Name proseLayer st = B.border $ C.hCenterLayer $ vLimit 8 $ viewport Prose Vertical $ vBox $ map str $ lines (st^.prose) infoLayer :: St -> Widget Name infoLayer st = T.Widget T.Fixed T.Fixed $ do c <- T.getContext let h = c^.T.availHeightL msg = case st^.lastReportedClick of Nothing -> "Click and hold/drag to report a mouse click" Just (name, T.Location l) -> "Mouse down at " <> show name <> " @ " <> show l T.render $ translateBy (T.Location (0, h-1)) $ clickable Info $ withDefAttr (attrName "info") $ C.hCenter $ str msg appEvent :: T.BrickEvent Name e -> T.EventM Name St () appEvent ev@(T.MouseDown n _ _ loc) = do lastReportedClick .= Just (n, loc) zoom edit $ E.handleEditorEvent ev appEvent (T.MouseUp {}) = lastReportedClick .= Nothing appEvent (T.VtyEvent (V.EvMouseUp {})) = lastReportedClick .= Nothing appEvent (T.VtyEvent (V.EvKey V.KUp [V.MCtrl])) = M.vScrollBy (M.viewportScroll Prose) (-1) appEvent (T.VtyEvent (V.EvKey V.KDown [V.MCtrl])) = M.vScrollBy (M.viewportScroll Prose) 1 appEvent (T.VtyEvent (V.EvKey V.KEsc [])) = M.halt appEvent ev = zoom edit $ E.handleEditorEvent ev aMap :: AttrMap aMap = attrMap V.defAttr [ (attrName "info", V.white `on` V.magenta) , (attrName "button1", V.white `on` V.cyan) , (attrName "button2", V.white `on` V.green) , (attrName "button3", V.white `on` V.blue) , (E.editFocusedAttr, V.black `on` V.yellow) ] app :: M.App St e Name app = M.App { M.appDraw = drawUi , M.appStartEvent = do vty <- M.getVtyHandle liftIO $ V.setMode (V.outputIface vty) V.Mouse True , M.appHandleEvent = appEvent , M.appAttrMap = const aMap , M.appChooseCursor = M.showFirstCursor } main :: IO () main = do void $ M.defaultMain app $ St [] Nothing (unlines [ "Try clicking on various UI elements." , "Observe that the click coordinates identify the" , "underlying widget coordinates." , "" , "Lorem ipsum dolor sit amet," , "consectetur adipiscing elit," , "sed do eiusmod tempor incididunt ut labore" , "et dolore magna aliqua." , "" , "Ut enim ad minim veniam" , "quis nostrud exercitation ullamco laboris" , "isi ut aliquip ex ea commodo consequat." , "" , "Duis aute irure dolor in reprehenderit" , "in voluptate velit esse cillum dolore eu fugiat nulla pariatur." , "" , "Excepteur sint occaecat cupidatat not proident," , "sunt in culpa qui officia deserunt mollit" , "anim id est laborum." ]) (E.editor TextBox Nothing "")