packages feed

matterhorn-50200.4.0: src/Draw/ListOverlay.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

module Draw.ListOverlay
  ( drawListOverlay
  )
where

import           Prelude ()
import           Prelude.MH

import           Brick
import           Brick.Widgets.Border
import           Brick.Widgets.Center
import           Brick.Widgets.Edit
import qualified Brick.Widgets.List as L
import           Control.Monad.Trans.Reader ( withReaderT )
import qualified Data.Foldable as F
import qualified Data.Text as T
import           Lens.Micro.Platform ( (%~) )

import           Themes
import           Types


hLimitWithPadding :: Int -> Widget n -> Widget n
hLimitWithPadding pad contents = Widget
  { hSize  = Fixed
  , vSize  = (vSize contents)
  , render =
      withReaderT (& availWidthL  %~ (\ n -> n - (2 * pad))) $ render $ cropToContext contents
  }

-- | Draw a ListOverlayState. This draws a bordered box with the
-- overlay's search input and results list inside the box. The provided
-- functions determine how to render the overlay in various states.
drawListOverlay :: ListOverlayState a b
                -- ^ The overlay state
                -> (b -> Widget Name)
                -- ^ The function to build the window title from the
                -- current search scope
                -> (b -> Widget Name)
                -- ^ The function to generate a message for the search
                -- scope indicating that no results were found
                -> (b -> Widget Name)
                -- ^ The function to generate the editor prompt for the
                -- search scope
                -> (Bool -> a -> Widget Name)
                -- ^ The function to render an item from the overlay's
                -- list
                -> Widget Name
drawListOverlay st scopeHeader scopeNoResults scopePrompt renderItem =
  centerLayer $ hLimitWithPadding 10 $ vLimit 25 $
  borderWithLabel (scopeHeader scope) body
  where
      body = vBox [ (padRight (Pad 1) promptMsg) <+>
                    renderEditor (txt . T.unlines) True (st^.listOverlaySearchInput)
                  , cursorPositionBorder
                  , showResults
                  ]
      plural 1 = ""
      plural _ = "s"
      cursorPositionBorder =
          if st^.listOverlaySearching
          then hBorderWithLabel $ txt "[Searching...]"
          else case st^.listOverlaySearchResults.L.listSelectedL of
              Nothing -> hBorder
              Just _ ->
                  let msg = "Showing " <> show numSearchResults <> " result" <> plural numSearchResults
                  in hBorderWithLabel $ str $ "[" <> msg <> "]"

      scope = st^.listOverlaySearchScope
      promptMsg = scopePrompt scope

      showMessage = center . withDefAttr clientEmphAttr

      showResults
        | numSearchResults == 0 = showMessage $ scopeNoResults scope
        | otherwise = renderedUserList

      renderedUserList = L.renderList renderItem True (st^.listOverlaySearchResults)
      numSearchResults = F.length $ st^.listOverlaySearchResults.L.listElementsL