Add support for requesting visible regions from EventM

This change adds a function, Brick.Main.makeVisible, which can be used
from EventM to request that a region (specified by its resource name) be
scrolled into view on the next rendering. This requires the region to be
named in the drawing using either reportExtent or clickable (which just
calls reportExtent). If the specified region is in a viewport, this will
result in the same behavior as if 'visible' was used to wrap the
specified region.
This commit is contained in:
Jonathan Daugherty 2022-01-18 12:51:54 -08:00
parent 7760d8defc
commit 55857c76c1
3 changed files with 29 additions and 3 deletions

View File

@ -13,6 +13,7 @@ module Brick.Main
, continueWithoutRedraw
, halt
, suspendAndResume
, makeVisible
, lookupViewport
, lookupExtent
, findClickedExtents
@ -275,7 +276,7 @@ customMainWithVty initialVty buildVty mUserChan app initialAppState = do
newVty <- buildVty
run newVty (newRS { renderCache = mempty }) newAppState brickChan
let emptyES = ES [] mempty
let emptyES = ES [] mempty mempty
emptyRS = RS M.empty mempty S.empty mempty mempty
eventRO = EventRO M.empty initialVty mempty emptyRS
@ -364,7 +365,7 @@ runVty vty readEvent app appState rs prevExtents draw = do
_ -> return (e, firstRS, exts)
_ -> return (e, firstRS, exts)
let emptyES = ES [] mempty
let emptyES = ES [] mempty mempty
eventRO = EventRO (viewportMap nextRS) vty nextExts nextRS
(next, eState) <- runStateT (runReaderT (runEventM (appHandleEvent app appState e'))
@ -579,3 +580,11 @@ halt = return . Halt
-- to the user.
suspendAndResume :: IO s -> EventM n (Next s)
suspendAndResume = return . SuspendAndResume
-- | Request that the specified UI element be made visible on the
-- next rendering. This is provided to allow event handlers to make
-- visibility requests in the same way that the 'visible' function does
-- at rendering time.
makeVisible :: (Ord n) => n -> EventM n ()
makeVisible n = EventM $ do
lift $ modify (\s -> s { requestedVisibleNames = S.insert n $ requestedVisibleNames s })

View File

@ -222,6 +222,7 @@ data CacheInvalidateRequest n =
data EventState n = ES { esScrollRequests :: [(n, ScrollRequest)]
, cacheInvalidateRequests :: S.Set (CacheInvalidateRequest n)
, requestedVisibleNames :: S.Set n
}
-- | An extent of a named area: its size, location, and origin.

View File

@ -225,6 +225,12 @@ addDynBorderOffset off r = r & bordersL %~ BM.translate off
-- | Render the specified widget and record its rendering extent using
-- the specified name (see also 'lookupExtent').
--
-- This function is the counterpart to 'makeVisible'; any visibility
-- requests made with 'makeVisible' must have a corresponding
-- 'reportExtent' in order to work. The 'clickable' function will also
-- work for this purpose to tell the renderer about the clickable
-- region.
reportExtent :: n -> Widget n -> Widget n
reportExtent n p =
Widget (hSize p) (vSize p) $ do
@ -233,9 +239,19 @@ reportExtent n p =
sz = ( result^.imageL.to V.imageWidth
, result^.imageL.to V.imageHeight
)
return $ result & extentsL %~ (ext:)
-- If the reported extent also has a visibility request
-- from EventM via makeVisible, add a visibility request to
-- the render state so this gets scrolled into view by any
-- containing viewport.
let addVisReq = if sz^._1 > 0 && sz^._2 > 0
then visibilityRequestsL %~ (VR (Location (0, 0)) sz :)
else id
return $ addVisReq $ result & extentsL %~ (ext:)
-- | Request mouse click events on the specified widget.
--
-- Regions used with 'clickable' can be scrolled into view with
-- 'makeVisible'.
clickable :: n -> Widget n -> Widget n
clickable n p =
Widget (hSize p) (vSize p) $ do