{-# LANGUAGE ExistentialQuantification, TypeSynonymInstances, FlexibleInstances #-}-- |This module provides visual borders to be placed between and-- around widgets. Border widgets in this module use the active-- 'Skin' in the 'RenderContext'.moduleGraphics.Vty.Widgets.Borders(HasBorderAttr(..),Bordered,HBorder,VBorder-- * Border Widget Constructors,vBorder,hBorder,bordered-- * Setting Attributes and Labels,withBorderAttribute,withHBorderLabel,withBorderedLabel,setHBorderLabel,setBorderedLabel)whereimportqualifiedData.TextasTimportGraphics.VtyimportGraphics.Vty.Widgets.CoreimportGraphics.Vty.Widgets.BoximportGraphics.Vty.Widgets.TextimportGraphics.Vty.Widgets.UtilimportGraphics.Vty.Widgets.Skins-- |The class of types with a border attribute, which differs from the-- normal and focused attributes.classHasBorderAttrawheresetBorderAttribute::a->Attr->IO()dataHBorder=HBorderAttrT.Textderiving(Show)instanceHasBorderAttr(WidgetHBorder)wheresetBorderAttributeta=updateWidgetStatet$\(HBordera's)->HBorder(mergeAttraa')s-- | Sets the border attribute of a thing with a border attribute.withBorderAttribute::(HasBorderAttra)=>Attr->a->IOawithBorderAttributeattw=setBorderAttributewatt>>returnw-- | Adds a label to a horizontal border. The label will be-- horizontally centered.withHBorderLabel::T.Text->WidgetHBorder->IO(WidgetHBorder)withHBorderLabellabelw=setHBorderLabelwlabel>>returnw-- | Adds a label to a horizontal border. The label will be-- horizontally centered.setHBorderLabel::WidgetHBorder->T.Text->IO()setHBorderLabelwlabel=updateWidgetStatew$\(HBordera_)->HBorderalabel-- | Adds a label to the top border of a bordered widget. The label-- will be horizontally centered.withBorderedLabel::T.Text->Widget(Bordereda)->IO(Widget(Bordereda))withBorderedLabellabelw=setBorderedLabelwlabel>>returnw-- | Adds a label to the top border of a bordered widget. The label-- will be horizontally centered.setBorderedLabel::Widget(Bordereda)->T.Text->IO()setBorderedLabelwlabel=updateWidgetStatew$\(Borderedach_)->Borderedachlabel-- |Create a single-row horizontal border using the specified-- attribute and character.hBorder::IO(WidgetHBorder)hBorder=doletinitSt=HBorderdef_attrT.emptywRef<-newWidgetinitSt$\w->w{growHorizontal_=const$returnTrue,render_=renderHBorder,getCursorPosition_=const$returnNothing}returnwRefrenderHBorder::WidgetHBorder->DisplayRegion->RenderContext->IOImagerenderHBorder_(DisplayRegion0_)_=returnempty_imagerenderHBorder_(DisplayRegion_0)_=returnempty_imagerenderHBorderthissctx=doHBorderattrstr<-getStatethisletattr'=mergeAttrs[overrideAttrctx,attr,normalAttrctx]ch=skinHorizontal$skinctxnoTitle=T.pack$replicate(fromEnum$region_widths)chwStr<-caseT.nullstrofTrue->returnnoTitleFalse->dolettitle=T.concat[T.pack" ",str,T.pack" "]case(textWidthtitle)>(Phys$fromEnum$region_widths)ofTrue->returnnoTitleFalse->doletremaining=(Phys$fromEnum$region_widths)-(textWidthtitle)Physside1=remaining`div`Phys2side2=ifremaining`mod`Phys2==Phys0thenside1elseside1+1return$T.concat[T.pack$replicateside1ch,title,T.pack$replicateside2ch]w<-plainTextWithAttrs[(wStr,attr')]renderwsctxdataVBorder=VBorderAttrderiving(Show)instanceHasBorderAttr(WidgetVBorder)wheresetBorderAttributeta=updateWidgetStatet$\(VBordera')->VBorder(mergeAttraa')-- |Create a single-column vertical border using the specified-- attribute and character.vBorder::IO(WidgetVBorder)vBorder=doletinitSt=VBorderdef_attrwRef<-newWidgetinitSt$\w->w{growVertical_=const$returnTrue,getCursorPosition_=const$returnNothing,render_=\thissctx->doVBorderattr<-getStatethisletattr'=mergeAttrs[overrideAttrctx,attr,normalAttrctx]return$char_fillattr'(skinVertical$skinctx)1(region_heights)}returnwRefdataBordereda=(Showa)=>BorderedAttr(Widgeta)T.TextinstanceShow(Bordereda)whereshow(Borderedattr_l)=concat["Bordered { attr = ",showattr,", label = ",showl,", ... }"]instanceHasBorderAttr(Widget(Bordereda))wheresetBorderAttributeta=updateWidgetStatet$\(Bordereda'chs)->Bordered(mergeAttraa')chs-- |Wrap a widget in a bordering box.bordered::(Showa)=>Widgeta->IO(Widget(Bordereda))borderedchild=doletinitSt=Bordereddef_attrchildT.emptywRef<-newWidgetinitSt$\w->w{growVertical_=const$growVerticalchild,growHorizontal_=const$growHorizontalchild,keyEventHandler=\thiskeymods->doBordered_ch_<-getStatethishandleKeyEventchkeymods,render_=\thissctx->dost<-getStatethisdrawBorderedstsctx,setCurrentPosition_=\thispos->doBordered_ch_<-getStatethisletchPos=pos`plusWidth`1`plusHeight`1setCurrentPositionchchPos}wRef`relayFocusEvents`childwRef`relayKeyEvents`childreturnwRefdrawBordered::(Showa)=>Bordereda->DisplayRegion->RenderContext->IOImagedrawBorderedthissctx|region_widths<2||region_heights<2=returnempty_image|otherwise=doletBorderedattrchildlabel=thisattr'=mergeAttrs[overrideAttrctx,attr,normalAttrctx]sk=skinctx-- Render the contained widget with enough room to draw borders.-- Then, use the size of the rendered widget to constrain the space-- used by the (expanding) borders.letconstrained=DisplayRegion(region_widths-2)(region_heights-2)childImage<-renderchildconstrainedctxletadjusted=DisplayRegion(image_widthchildImage+2)(image_heightchildImage)tlCorner<-plainText(T.singleton$skinCornerTLsk)>>=withNormalAttributeattr'trCorner<-plainText(T.singleton$skinCornerTRsk)>>=withNormalAttributeattr'blCorner<-plainText(T.singleton$skinCornerBLsk)>>=withNormalAttributeattr'brCorner<-plainText(T.singleton$skinCornerBRsk)>>=withNormalAttributeattr'hb<-hBorder>>=withHBorderLabellabelsetBorderAttributehbattr'topWidget<-hBoxtlCorner=<<hBoxhbtrCornertop<-rendertopWidgetadjustedctxhb2<-hBorderbottomWidget<-hBoxblCorner=<<hBoxhb2brCornerbottom<-renderbottomWidgetadjustedctxvb<-vBordersetBorderAttributevbattr'leftRight<-rendervbadjustedctxletmiddle=horiz_cat[leftRight,childImage,leftRight]return$vert_cat[top,middle,bottom]