Remove appLiftVtyEvent in favor of library event type BrickEvent

This change makes it possible for brick to extent the event space using
its own event notions in addition those provided by Vty and the
application itself. This means we no longer need the user to provide the
type and appLiftVtyEvent went away. This makes pattern-matching in event
handlers a little noisier with the benefit that we can now add events
like mouse clicks or drags to the event type.
This commit is contained in:
Jonathan Daugherty 2016-10-25 20:19:31 -07:00
parent 831092e1bd
commit fc8cfe3b4a
16 changed files with 100 additions and 104 deletions

View File

@ -3,7 +3,7 @@ module Main where
import Data.Monoid
import Graphics.Vty
( Event, Attr, white, blue, cyan, green, red, yellow
( Attr, white, blue, cyan, green, red, yellow
, black
)
@ -20,7 +20,7 @@ import Brick.Widgets.Core
import Brick.Util (on, fg)
import Brick.AttrMap (attrMap, AttrMap)
ui :: Widget ()
ui :: Widget n
ui =
vBox [ str "This text uses the global default attribute."
, withAttr "foundFull" $
@ -51,14 +51,13 @@ theMap = attrMap globalDefault
, ("general" <> "specific", fg cyan)
]
app :: App () Event ()
app :: App () e ()
app =
App { appDraw = const [ui]
, appHandleEvent = resizeOrQuit
, appStartEvent = return
, appAttrMap = const theMap
, appChooseCursor = neverShowCursor
, appLiftVtyEvent = id
}
main :: IO ()

View File

@ -14,6 +14,7 @@ import qualified Brick.Main as M
import qualified Brick.Widgets.Center as C
import Brick.Types
( Widget
, BrickEvent(..)
)
import Brick.Widgets.Core
( vBox
@ -57,22 +58,21 @@ drawUi i = [ui]
, str "'Esc' to quit."
]
appEvent :: Int -> V.Event -> T.EventM Name (T.Next Int)
appEvent i (V.EvKey (V.KChar '+') []) = M.continue $ i + 1
appEvent i (V.EvKey (V.KChar 'i') []) = M.invalidateCacheEntry ExpensiveWidget >> M.continue i
appEvent i (V.EvKey V.KEsc []) = M.halt i
appEvent :: Int -> BrickEvent Name e -> T.EventM Name (T.Next Int)
appEvent i (VtyEvent (V.EvKey (V.KChar '+') [])) = M.continue $ i + 1
appEvent i (VtyEvent (V.EvKey (V.KChar 'i') [])) = M.invalidateCacheEntry ExpensiveWidget >> M.continue i
appEvent i (VtyEvent (V.EvKey V.KEsc [])) = M.halt i
appEvent i _ = M.continue i
emphAttr :: AttrName
emphAttr = "emphasis"
app :: M.App Int V.Event Name
app :: M.App Int e Name
app =
M.App { M.appDraw = drawUi
, M.appStartEvent = return
, M.appHandleEvent = appEvent
, M.appAttrMap = const $ attrMap V.defAttr [(emphAttr, V.white `on` V.blue)]
, M.appLiftVtyEvent = id
, M.appChooseCursor = M.neverShowCursor
}

View File

@ -21,39 +21,40 @@ import Brick.Types
( Widget
, Next
, EventM
, BrickEvent(..)
)
import Brick.Widgets.Core
( (<=>)
, str
)
data CustomEvent = Counter deriving Show
data St =
St { _stLastVtyEvent :: Maybe V.Event
St { _stLastBrickEvent :: Maybe (BrickEvent () CustomEvent)
, _stCounter :: Int
}
makeLenses ''St
data CustomEvent = VtyEvent V.Event
| Counter
drawUI :: St -> [Widget ()]
drawUI st = [a]
where
a = (str $ "Last Vty event: " <> (show $ st^.stLastVtyEvent))
a = (str $ "Last event: " <> (show $ st^.stLastBrickEvent))
<=>
(str $ "Counter value is: " <> (show $ st^.stCounter))
appEvent :: St -> CustomEvent -> EventM () (Next St)
appEvent :: St -> BrickEvent () CustomEvent -> EventM () (Next St)
appEvent st e =
case e of
VtyEvent (V.EvKey V.KEsc []) -> halt st
VtyEvent ev -> continue $ st & stLastVtyEvent .~ (Just ev)
Counter -> continue $ st & stCounter %~ (+1)
VtyEvent _ -> continue $ st & stLastBrickEvent .~ (Just e)
AppEvent Counter -> continue $ st & stCounter %~ (+1)
& stLastBrickEvent .~ (Just e)
initialState :: St
initialState =
St { _stLastVtyEvent = Nothing
St { _stLastBrickEvent = Nothing
, _stCounter = 0
}
@ -64,7 +65,6 @@ theApp =
, appHandleEvent = appEvent
, appStartEvent = return
, appAttrMap = def
, appLiftVtyEvent = VtyEvent
}
main :: IO ()

View File

@ -7,6 +7,7 @@ import qualified Graphics.Vty as V
import qualified Brick.Main as M
import Brick.Types
( Widget
, BrickEvent(..)
)
import Brick.Widgets.Core
( padAll
@ -26,12 +27,13 @@ drawUI d = [ui]
where
ui = D.renderDialog d $ C.hCenter $ padAll 1 $ str "This is the dialog body."
appEvent :: D.Dialog Choice -> V.Event -> T.EventM () (T.Next (D.Dialog Choice))
appEvent d ev =
appEvent :: D.Dialog Choice -> BrickEvent () e -> T.EventM () (T.Next (D.Dialog Choice))
appEvent d (VtyEvent ev) =
case ev of
V.EvKey V.KEsc [] -> M.halt d
V.EvKey V.KEnter [] -> M.halt d
_ -> M.continue =<< D.handleDialogEvent ev d
appEvent d _ = M.continue d
initialState :: D.Dialog Choice
initialState = D.dialog (Just "Title") (Just (0, choices)) 50
@ -48,14 +50,13 @@ theMap = A.attrMap V.defAttr
, (D.buttonSelectedAttr, bg V.yellow)
]
theApp :: M.App (D.Dialog Choice) V.Event ()
theApp :: M.App (D.Dialog Choice) e ()
theApp =
M.App { M.appDraw = drawUI
, M.appChooseCursor = M.showFirstCursor
, M.appHandleEvent = appEvent
, M.appStartEvent = return
, M.appAttrMap = const theMap
, M.appLiftVtyEvent = id
}
main :: IO ()

View File

@ -47,8 +47,8 @@ drawUI st = [ui]
str " " <=>
str "Press Tab to switch between editors, Esc to quit."
appEvent :: St -> V.Event -> T.EventM Name (T.Next St)
appEvent st ev =
appEvent :: St -> T.BrickEvent Name e -> T.EventM Name (T.Next St)
appEvent st (T.VtyEvent ev) =
case ev of
V.EvKey V.KEsc [] -> M.halt st
V.EvKey (V.KChar '\t') [] -> M.continue $ st & focusRing %~ F.focusNext
@ -58,6 +58,7 @@ appEvent st ev =
Just Edit1 -> T.handleEventLensed st edit1 E.handleEditorEvent ev
Just Edit2 -> T.handleEventLensed st edit2 E.handleEditorEvent ev
Nothing -> return st
appEvent st _ = M.continue st
initialState :: St
initialState =
@ -74,14 +75,13 @@ theMap = A.attrMap V.defAttr
appCursor :: St -> [T.CursorLocation Name] -> Maybe (T.CursorLocation Name)
appCursor = F.focusRingCursor (^.focusRing)
theApp :: M.App St V.Event Name
theApp :: M.App St e Name
theApp =
M.App { M.appDraw = drawUI
, M.appChooseCursor = appCursor
, M.appHandleEvent = appEvent
, M.appStartEvent = return
, M.appAttrMap = const theMap
, M.appLiftVtyEvent = id
}
main :: IO ()

View File

@ -43,27 +43,26 @@ bottomLayer st =
translateBy (st^.bottomLayerLocation) $
B.border $ str "Bottom layer\n(Ctrl-arrow keys move)"
appEvent :: St -> V.Event -> T.EventM () (T.Next St)
appEvent st (V.EvKey V.KDown []) = M.continue $ st & topLayerLocation.rowL %~ (+ 1)
appEvent st (V.EvKey V.KUp []) = M.continue $ st & topLayerLocation.rowL %~ (subtract 1)
appEvent st (V.EvKey V.KRight []) = M.continue $ st & topLayerLocation.columnL %~ (+ 1)
appEvent st (V.EvKey V.KLeft []) = M.continue $ st & topLayerLocation.columnL %~ (subtract 1)
appEvent :: St -> T.BrickEvent () e -> T.EventM () (T.Next St)
appEvent st (T.VtyEvent (V.EvKey V.KDown [])) = M.continue $ st & topLayerLocation.rowL %~ (+ 1)
appEvent st (T.VtyEvent (V.EvKey V.KUp [])) = M.continue $ st & topLayerLocation.rowL %~ (subtract 1)
appEvent st (T.VtyEvent (V.EvKey V.KRight [])) = M.continue $ st & topLayerLocation.columnL %~ (+ 1)
appEvent st (T.VtyEvent (V.EvKey V.KLeft [])) = M.continue $ st & topLayerLocation.columnL %~ (subtract 1)
appEvent st (V.EvKey V.KDown [V.MCtrl]) = M.continue $ st & bottomLayerLocation.rowL %~ (+ 1)
appEvent st (V.EvKey V.KUp [V.MCtrl]) = M.continue $ st & bottomLayerLocation.rowL %~ (subtract 1)
appEvent st (V.EvKey V.KRight [V.MCtrl]) = M.continue $ st & bottomLayerLocation.columnL %~ (+ 1)
appEvent st (V.EvKey V.KLeft [V.MCtrl]) = M.continue $ st & bottomLayerLocation.columnL %~ (subtract 1)
appEvent st (T.VtyEvent (V.EvKey V.KDown [V.MCtrl])) = M.continue $ st & bottomLayerLocation.rowL %~ (+ 1)
appEvent st (T.VtyEvent (V.EvKey V.KUp [V.MCtrl])) = M.continue $ st & bottomLayerLocation.rowL %~ (subtract 1)
appEvent st (T.VtyEvent (V.EvKey V.KRight [V.MCtrl])) = M.continue $ st & bottomLayerLocation.columnL %~ (+ 1)
appEvent st (T.VtyEvent (V.EvKey V.KLeft [V.MCtrl])) = M.continue $ st & bottomLayerLocation.columnL %~ (subtract 1)
appEvent st (V.EvKey V.KEsc []) = M.halt st
appEvent st (T.VtyEvent (V.EvKey V.KEsc [])) = M.halt st
appEvent st _ = M.continue st
app :: M.App St V.Event ()
app :: M.App St e ()
app =
M.App { M.appDraw = drawUi
, M.appStartEvent = return
, M.appHandleEvent = appEvent
, M.appAttrMap = const def
, M.appLiftVtyEvent = id
, M.appChooseCursor = M.neverShowCursor
}

View File

@ -45,8 +45,8 @@ drawUI l = [ui]
, C.hCenter $ str "Press Esc to exit."
]
appEvent :: L.List () Char -> V.Event -> T.EventM () (T.Next (L.List () Char))
appEvent l e =
appEvent :: L.List () Char -> T.BrickEvent () e -> T.EventM () (T.Next (L.List () Char))
appEvent l (T.VtyEvent e) =
case e of
V.EvKey (V.KChar '+') [] ->
let el = nextElement (L.listElements l)
@ -64,6 +64,7 @@ appEvent l e =
where
nextElement :: Vec.Vector Char -> Char
nextElement v = fromMaybe '?' $ Vec.find (flip Vec.notElem v) (Vec.fromList ['a' .. 'z'])
appEvent l _ = M.continue l
listDrawElement :: (Show a) => Bool -> a -> Widget ()
listDrawElement sel a =
@ -85,14 +86,13 @@ theMap = A.attrMap V.defAttr
, (customAttr, fg V.cyan)
]
theApp :: M.App (L.List () Char) V.Event ()
theApp :: M.App (L.List () Char) e ()
theApp =
M.App { M.appDraw = drawUI
, M.appChooseCursor = M.showFirstCursor
, M.appHandleEvent = appEvent
, M.appStartEvent = return
, M.appAttrMap = const theMap
, M.appLiftVtyEvent = id
}
main :: IO ()

View File

@ -32,14 +32,13 @@ theMap = attrMap V.defAttr
, ("keyword2", V.white `on` V.blue)
]
app :: App () V.Event ()
app :: App () e ()
app =
App { appDraw = const [ui]
, appHandleEvent = resizeOrQuit
, appAttrMap = const theMap
, appStartEvent = return
, appChooseCursor = neverShowCursor
, appLiftVtyEvent = id
}
main :: IO ()

View File

@ -68,9 +68,9 @@ draggableLayer st =
"clicking and dragging anywhere\n" <>
"on or within its border.") <+> fill ' '
appEvent :: St -> V.Event -> T.EventM Name (T.Next St)
appEvent st (V.EvKey V.KEsc []) = M.halt st
appEvent st ev = do
appEvent :: St -> T.BrickEvent Name e -> T.EventM Name (T.Next St)
appEvent st (T.VtyEvent (V.EvKey V.KEsc [])) = M.halt st
appEvent st (T.VtyEvent ev) = do
Just e <- M.lookupExtent Layer
M.continue =<< case ev of
-- If the mouse button was released, stop dragging.
@ -99,6 +99,7 @@ appEvent st ev = do
es <- M.findClickedExtents (c, r)
return $ st' & clicked .~ es
_ -> return st
appEvent st _ = M.continue st
aMap :: AttrMap
aMap = attrMap V.defAttr
@ -106,13 +107,12 @@ aMap = attrMap V.defAttr
, ("dragging", V.black `on` V.yellow)
]
app :: M.App St V.Event Name
app :: M.App St e Name
app =
M.App { M.appDraw = drawUi
, M.appStartEvent = return
, M.appHandleEvent = appEvent
, M.appAttrMap = const aMap
, M.appLiftVtyEvent = id
, M.appChooseCursor = M.neverShowCursor
}

View File

@ -2,7 +2,6 @@
module Main where
import Data.Default
import qualified Graphics.Vty as V
import Brick.Main (App(..), neverShowCursor, resizeOrQuit, defaultMain)
import Brick.Types
@ -46,14 +45,13 @@ ui =
, padAll 2 $ str "Padded by 2 on all sides"
]
app :: App () V.Event ()
app :: App () e ()
app =
App { appDraw = const [ui]
, appHandleEvent = resizeOrQuit
, appStartEvent = return
, appAttrMap = const def
, appChooseCursor = neverShowCursor
, appLiftVtyEvent = id
}
main :: IO ()

View File

@ -17,6 +17,7 @@ import Brick.Types
( Widget
, EventM
, Next
, BrickEvent(..)
)
import Brick.Widgets.Core
( vBox
@ -36,8 +37,8 @@ drawUI st = [ui]
, str "(Press Esc to quit or Space to ask for input)"
]
appEvent :: St -> V.Event -> EventM () (Next St)
appEvent st e =
appEvent :: St -> BrickEvent () e -> EventM () (Next St)
appEvent st (VtyEvent e) =
case e of
V.EvKey V.KEsc [] -> halt st
V.EvKey (V.KChar ' ') [] -> suspendAndResume $ do
@ -45,20 +46,20 @@ appEvent st e =
s <- getLine
return $ st & stExternalInput .~ s
_ -> continue st
appEvent st _ = continue st
initialState :: St
initialState =
St { _stExternalInput = ""
}
theApp :: App St V.Event ()
theApp :: App St e ()
theApp =
App { appDraw = drawUI
, appChooseCursor = neverShowCursor
, appHandleEvent = appEvent
, appStartEvent = return
, appAttrMap = const def
, appLiftVtyEvent = id
}
main :: IO ()

View File

@ -58,25 +58,24 @@ vp2Scroll = M.viewportScroll VP2
vp3Scroll :: M.ViewportScroll Name
vp3Scroll = M.viewportScroll VP3
appEvent :: () -> V.Event -> T.EventM Name (T.Next ())
appEvent _ (V.EvKey V.KDown [V.MCtrl]) = M.vScrollBy vp3Scroll 1 >> M.continue ()
appEvent _ (V.EvKey V.KUp [V.MCtrl]) = M.vScrollBy vp3Scroll (-1) >> M.continue ()
appEvent _ (V.EvKey V.KRight [V.MCtrl]) = M.hScrollBy vp3Scroll 1 >> M.continue ()
appEvent _ (V.EvKey V.KLeft [V.MCtrl]) = M.hScrollBy vp3Scroll (-1) >> M.continue ()
appEvent _ (V.EvKey V.KDown []) = M.vScrollBy vp1Scroll 1 >> M.continue ()
appEvent _ (V.EvKey V.KUp []) = M.vScrollBy vp1Scroll (-1) >> M.continue ()
appEvent _ (V.EvKey V.KRight []) = M.hScrollBy vp2Scroll 1 >> M.continue ()
appEvent _ (V.EvKey V.KLeft []) = M.hScrollBy vp2Scroll (-1) >> M.continue ()
appEvent _ (V.EvKey V.KEsc []) = M.halt ()
appEvent :: () -> T.BrickEvent Name e -> T.EventM Name (T.Next ())
appEvent _ (T.VtyEvent (V.EvKey V.KDown [V.MCtrl])) = M.vScrollBy vp3Scroll 1 >> M.continue ()
appEvent _ (T.VtyEvent (V.EvKey V.KUp [V.MCtrl])) = M.vScrollBy vp3Scroll (-1) >> M.continue ()
appEvent _ (T.VtyEvent (V.EvKey V.KRight [V.MCtrl])) = M.hScrollBy vp3Scroll 1 >> M.continue ()
appEvent _ (T.VtyEvent (V.EvKey V.KLeft [V.MCtrl])) = M.hScrollBy vp3Scroll (-1) >> M.continue ()
appEvent _ (T.VtyEvent (V.EvKey V.KDown [])) = M.vScrollBy vp1Scroll 1 >> M.continue ()
appEvent _ (T.VtyEvent (V.EvKey V.KUp [])) = M.vScrollBy vp1Scroll (-1) >> M.continue ()
appEvent _ (T.VtyEvent (V.EvKey V.KRight [])) = M.hScrollBy vp2Scroll 1 >> M.continue ()
appEvent _ (T.VtyEvent (V.EvKey V.KLeft [])) = M.hScrollBy vp2Scroll (-1) >> M.continue ()
appEvent _ (T.VtyEvent (V.EvKey V.KEsc [])) = M.halt ()
appEvent _ _ = M.continue ()
app :: M.App () V.Event Name
app :: M.App () e Name
app =
M.App { M.appDraw = drawUi
, M.appStartEvent = return
, M.appHandleEvent = appEvent
, M.appAttrMap = const def
, M.appLiftVtyEvent = id
, M.appChooseCursor = M.neverShowCursor
}

View File

@ -99,16 +99,16 @@ vp2Scroll = M.viewportScroll VP2
vp3Scroll :: M.ViewportScroll Name
vp3Scroll = M.viewportScroll VP3
appEvent :: St -> V.Event -> T.EventM Name (T.Next St)
appEvent st (V.EvKey V.KDown [V.MCtrl]) = M.continue $ st & vp3Index._1 %~ min (vp3Size^._1) . (+ 1)
appEvent st (V.EvKey V.KUp [V.MCtrl]) = M.continue $ st & vp3Index._1 %~ max 1 . subtract 1
appEvent st (V.EvKey V.KRight [V.MCtrl]) = M.continue $ st & vp3Index._2 %~ min (vp3Size^._1) . (+ 1)
appEvent st (V.EvKey V.KLeft [V.MCtrl]) = M.continue $ st & vp3Index._2 %~ max 1 . subtract 1
appEvent st (V.EvKey V.KDown []) = M.continue $ st & vp1Index %~ min vp1Size . (+ 1)
appEvent st (V.EvKey V.KUp []) = M.continue $ st & vp1Index %~ max 1 . subtract 1
appEvent st (V.EvKey V.KRight []) = M.continue $ st & vp2Index %~ min vp2Size . (+ 1)
appEvent st (V.EvKey V.KLeft []) = M.continue $ st & vp2Index %~ max 1 . subtract 1
appEvent st (V.EvKey V.KEsc []) = M.halt st
appEvent :: St -> T.BrickEvent Name e -> T.EventM Name (T.Next St)
appEvent st (T.VtyEvent (V.EvKey V.KDown [V.MCtrl])) = M.continue $ st & vp3Index._1 %~ min (vp3Size^._1) . (+ 1)
appEvent st (T.VtyEvent (V.EvKey V.KUp [V.MCtrl])) = M.continue $ st & vp3Index._1 %~ max 1 . subtract 1
appEvent st (T.VtyEvent (V.EvKey V.KRight [V.MCtrl])) = M.continue $ st & vp3Index._2 %~ min (vp3Size^._1) . (+ 1)
appEvent st (T.VtyEvent (V.EvKey V.KLeft [V.MCtrl])) = M.continue $ st & vp3Index._2 %~ max 1 . subtract 1
appEvent st (T.VtyEvent (V.EvKey V.KDown [])) = M.continue $ st & vp1Index %~ min vp1Size . (+ 1)
appEvent st (T.VtyEvent (V.EvKey V.KUp [])) = M.continue $ st & vp1Index %~ max 1 . subtract 1
appEvent st (T.VtyEvent (V.EvKey V.KRight [])) = M.continue $ st & vp2Index %~ min vp2Size . (+ 1)
appEvent st (T.VtyEvent (V.EvKey V.KLeft [])) = M.continue $ st & vp2Index %~ max 1 . subtract 1
appEvent st (T.VtyEvent (V.EvKey V.KEsc [])) = M.halt st
appEvent st _ = M.continue st
theMap :: AttrMap
@ -116,13 +116,12 @@ theMap = attrMap V.defAttr
[ (selectedAttr, V.black `on` V.yellow)
]
app :: M.App St V.Event Name
app :: M.App St e Name
app =
M.App { M.appDraw = drawUi
, M.appStartEvent = return
, M.appHandleEvent = appEvent
, M.appAttrMap = const theMap
, M.appLiftVtyEvent = id
, M.appChooseCursor = M.neverShowCursor
}

View File

@ -107,7 +107,7 @@ data App s e n =
-- is that many widgets may request a cursor placement but your
-- application state is what you probably want to use to decide
-- which one wins.
, appHandleEvent :: s -> e -> EventM n (Next s)
, appHandleEvent :: s -> BrickEvent n e -> EventM n (Next s)
-- ^ This function takes the current application state and an
-- event and returns an action to be taken and a corresponding
-- transformed application state. Possible options are
@ -118,17 +118,13 @@ data App s e n =
-- initial scrolling requests, for example.
, appAttrMap :: s -> AttrMap
-- ^ The attribute map that should be used during rendering.
, appLiftVtyEvent :: Event -> e
-- ^ The event constructor to use to wrap Vty events in your own
-- event type. For example, if the application's event type is
-- 'Event', this is just 'id'.
}
-- | The default main entry point which takes an application and an
-- initial state and returns the final state returned by a 'halt'
-- operation.
defaultMain :: (Ord n)
=> App s Event n
=> App s e n
-- ^ The application.
-> s
-- ^ The initial application state.
@ -149,7 +145,6 @@ simpleMain w =
, appHandleEvent = resizeOrQuit
, appStartEvent = return
, appAttrMap = def
, appLiftVtyEvent = id
, appChooseCursor = neverShowCursor
}
in defaultMain app ()
@ -159,8 +154,8 @@ simpleMain w =
-- a halt. This is a convenience function useful as an 'appHandleEvent'
-- value for simple applications using the 'Event' type that do not need
-- to get more sophisticated user input.
resizeOrQuit :: s -> Event -> EventM n (Next s)
resizeOrQuit s (EvResize _ _) = continue s
resizeOrQuit :: s -> BrickEvent n e -> EventM n (Next s)
resizeOrQuit s (VtyEvent (EvResize _ _)) = continue s
resizeOrQuit s _ = halt s
data InternalNext n a = InternalSuspendAndResume (RenderState n) (IO a)
@ -168,7 +163,7 @@ data InternalNext n a = InternalSuspendAndResume (RenderState n) (IO a)
runWithNewVty :: (Ord n)
=> IO Vty
-> Chan (Either Event e)
-> Chan (BrickEvent n e)
-> App s e n
-> RenderState n
-> s
@ -219,18 +214,18 @@ customMain buildVty userChan app initialAppState = do
(st, eState) <- runStateT (runReaderT (runEventM (appStartEvent app initialAppState)) eventRO) emptyES
let initialRS = RS M.empty (esScrollRequests eState) S.empty mempty
chan <- newChan
forkIO $ forever $ readChan userChan >>= (\userEvent -> writeChan chan (Right userEvent))
forkIO $ forever $ readChan userChan >>= (\userEvent -> writeChan chan $ AppEvent userEvent)
run initialRS st chan
supplyVtyEvents :: Vty -> Chan (Either Event e) -> IO ()
supplyVtyEvents :: Vty -> Chan (BrickEvent n e) -> IO ()
supplyVtyEvents vty chan =
forever $ do
e <- nextEvent vty
writeChan chan $ Left e
writeChan chan $ VtyEvent e
runVty :: (Ord n)
=> Vty
-> Chan (Either Event e)
-> Chan (BrickEvent n e)
-> App s e n
-> s
-> RenderState n
@ -243,17 +238,14 @@ runVty vty chan app appState rs = do
-- states before we invoke the event handler since we want the event
-- handler to have access to accurate viewport information.
(nextRS, nextExts) <- case e of
Left (EvResize _ _) ->
(VtyEvent (EvResize _ _)) ->
renderApp vty app appState $ firstRS & observedNamesL .~ S.empty
_ -> return (firstRS, exts)
let emptyES = ES [] []
userEvent = case e of
Left e' -> appLiftVtyEvent app e'
Right e' -> e'
eventRO = EventRO (viewportMap nextRS) (Just vty) nextExts
let eventRO = EventRO (viewportMap nextRS) (Just vty) nextExts
(next, eState) <- runStateT (runReaderT (runEventM (appHandleEvent app appState userEvent))
(next, eState) <- runStateT (runReaderT (runEventM (appHandleEvent app appState e))
eventRO) emptyES
return (next, nextRS { rsScrollRequests = esScrollRequests eState
, renderCache = applyInvalidations (cacheInvalidateRequests eState) $

View File

@ -25,6 +25,7 @@ module Brick.Types
-- * Event-handling types
, EventM(..)
, Next
, BrickEvent(..)
, handleEventLensed
-- * Rendering infrastructure
@ -76,7 +77,7 @@ import Lens.Micro (_1, _2, to, (^.), (&), (.~), Lens')
import Lens.Micro.Type (Getting)
import Control.Monad.Trans.State.Lazy
import Control.Monad.Trans.Reader
import Graphics.Vty (Event, Attr)
import Graphics.Vty (Attr)
import Control.Monad.IO.Class
import Brick.Types.TH

View File

@ -24,6 +24,7 @@ module Brick.Types.Internal
, Result(..)
, Extent(..)
, CacheInvalidateRequest(..)
, BrickEvent(..)
, rsScrollRequestsL
, viewportMapL
@ -48,7 +49,7 @@ import Lens.Micro.TH (makeLenses)
import Lens.Micro.Internal (Field1, Field2)
import qualified Data.Set as S
import qualified Data.Map as M
import Graphics.Vty (Vty, DisplayRegion, Image, emptyImage)
import Graphics.Vty (Vty, Event, DisplayRegion, Image, emptyImage)
import Data.Default (Default(..))
import Brick.Types.TH
@ -191,6 +192,13 @@ suffixLenses ''Result
instance Default (Result n) where
def = Result emptyImage [] [] []
-- | The type of events.
data BrickEvent n e = VtyEvent Event
-- ^ The event was a Vty event.
| AppEvent e
-- ^ The event was an application event.
deriving (Show, Eq)
data RenderState n =
RS { viewportMap :: M.Map n Viewport
, rsScrollRequests :: [(n, ScrollRequest)]