{-# LANGUAGE OverloadedStrings #-}
module Brick.Widgets.Border
(
border
, borderWithLabel
, hBorder
, hBorderWithLabel
, vBorder
, borderElem
, borderAttr
, joinableBorder
)
where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
import Lens.Micro ((^.), (&), (.~), to)
import Graphics.Vty (imageHeight, imageWidth)
import Brick.AttrMap
import Brick.Types
import Brick.Widgets.Core
import Brick.Widgets.Border.Style (BorderStyle(..))
import Brick.Widgets.Internal (renderDynBorder)
import Data.IMap (Run(..))
import qualified Brick.BorderMap as BM
borderAttr :: AttrName
borderAttr = "border"
borderElem :: (BorderStyle -> Char) -> Widget n
borderElem f =
Widget Fixed Fixed $ do
bs <- ctxBorderStyle <$> getContext
render $ withAttr borderAttr $ str [f bs]
border :: Widget n -> Widget n
border = border_ Nothing
borderWithLabel :: Widget n
-> Widget n
-> Widget n
borderWithLabel label = border_ (Just label)
border_ :: Maybe (Widget n) -> Widget n -> Widget n
border_ label wrapped =
Widget (hSize wrapped) (vSize wrapped) $ do
c <- getContext
middleResult <- render $ hLimit (c^.availWidthL - 2)
$ vLimit (c^.availHeightL - 2)
$ wrapped
let tl = joinableBorder (Edges False True False True)
tr = joinableBorder (Edges False True True False)
bl = joinableBorder (Edges True False False True)
br = joinableBorder (Edges True False True False)
top = tl <+> maybe hBorder hBorderWithLabel label <+> tr
bottom = bl <+> hBorder <+> br
middle = vBorder <+> (Widget Fixed Fixed $ return middleResult) <+> vBorder
total = top <=> middle <=> bottom
render $ hLimit (middleResult^.imageL.to imageWidth + 2)
$ vLimit (middleResult^.imageL.to imageHeight + 2)
$ total
hBorder :: Widget n
hBorder =
withAttr borderAttr $ Widget Greedy Fixed $ do
ctx <- getContext
let bs = ctxBorderStyle ctx
w = availWidth ctx
db <- dynBorderFromDirections (Edges False False True True)
let dynBorders = BM.insertH mempty (Run w db)
$ BM.emptyCoordinates (Edges 0 0 0 (w-1))
setDynBorders dynBorders $ render $ vLimit 1 $ fill (bsHorizontal bs)
hBorderWithLabel :: Widget n
-> Widget n
hBorderWithLabel label =
Widget Greedy Fixed $ do
res <- render $ vLimit 1 label
render $ hBox [hBorder, Widget Fixed Fixed (return res), hBorder]
vBorder :: Widget n
vBorder =
withAttr borderAttr $ Widget Fixed Greedy $ do
ctx <- getContext
let bs = ctxBorderStyle ctx
h = availHeight ctx
db <- dynBorderFromDirections (Edges True True False False)
let dynBorders = BM.insertV mempty (Run h db)
$ BM.emptyCoordinates (Edges 0 (h-1) 0 0)
setDynBorders dynBorders $ render $ hLimit 1 $ fill (bsVertical bs)
dynBorderFromDirections :: Edges Bool -> RenderM n DynBorder
dynBorderFromDirections dirs = do
ctx <- getContext
return DynBorder
{ dbStyle = ctxBorderStyle ctx
, dbAttr = attrMapLookup (ctxAttrName ctx) (ctxAttrMap ctx)
, dbSegments = (\draw -> BorderSegment True draw draw) <$> dirs
}
setDynBorders :: BM.BorderMap DynBorder -> RenderM n (Result n) -> RenderM n (Result n)
setDynBorders newBorders act = do
dyn <- ctxDynBorders <$> getContext
res <- act
return $ if dyn
then res & bordersL .~ newBorders
else res
joinableBorder :: Edges Bool -> Widget n
joinableBorder dirs = withAttr borderAttr . Widget Fixed Fixed $ do
db <- dynBorderFromDirections dirs
setDynBorders
(BM.singleton mempty db)
(render (raw (renderDynBorder db)))