packages feed

spade-0.1.0.0: src/UI/Widgets/LogWidget.hs

module UI.Widgets.LogWidget where

import Data.Text as T
import Text.Printf (printf)
import System.Console.ANSI (Color(..))
import Common
import Highlighter.Highlighter
import UI.Widgets.Common as C

data LogWidget = LogWidget
  { lwDim     :: Dimensions
  , lwContent :: [Text]
  , lwPos     :: ScreenPos
  , lwVisible :: Bool
  , lwScrollOffset :: Int
  }

insertLog :: WidgetC m => WRef LogWidget -> Text -> m ()
insertLog ref l = modifyWRef ref (\lw ->
  let
    h = diH $ lwDim lw
    ln = Prelude.length (lwContent lw)
    newContent = (lwContent lw) ++ [l]
  in if ln > h then lw { lwScrollOffset = 0, lwContent = Prelude.drop (ln - h) newContent } else lw { lwContent = newContent })

instance Moveable LogWidget where
  getPos ref = lwPos <$> readWRef ref
  move ref sp =
    modifyWRef ref (\ww -> ww { lwPos = sp })
  getDim ref =
    lwDim <$> readWRef ref
  resize ref cb =
    modifyWRef ref (\ww -> ww { lwDim = cb $ lwDim ww })

instance Widget LogWidget where
  hasCapability (MoveableCap _)  = Just Dict
  hasCapability (DrawableCap _)  = Just Dict
  hasCapability _            = Nothing

instance Drawable LogWidget where
  setVisibility ref v = modifyWRef ref (\b -> b { lwVisible = v })
  getVisibility ref = lwVisible <$> readWRef ref
  draw ref = do
    w <- readWRef ref
    let height = (diH $ lwDim w) - 3
    let width = (diW $ lwDim w) - 3
    let scrollOffset = lwScrollOffset w
    drawBorderBox (lwPos w) (lwDim w)
    wSetCursor $ moveDown 1 $ moveRight 1 (lwPos w)
    let fmt = "%-" <> (show (width + 1)) <> "s"
    csPutText $ colorText White Black (T.pack $ printf fmt (" Logs" :: Text))
    let lines' = Prelude.concat $ T.splitOn "\n" <$> lwContent w
    lst <- foldM (\offset line -> do
      let chunksize = (diW $ lwDim w) - 2
      let segments = T.chunksOf chunksize line
      foldM (\soffset chunk -> do
        when ((soffset > scrollOffset) && ((soffset - scrollOffset) <= height) ) $ do
          let cp = moveUp scrollOffset $ moveDown (soffset + 1)  $ moveRight 1 (lwPos w)
          wSetCursor cp
          csPutText $ Plain (T.replicate chunksize " ")
          wSetCursor cp
          csPutText $ Plain (T.strip chunk)
        pure (soffset + 1)
        ) offset segments
      ) 1 lines'
    let overflow = (((lst - 1) - scrollOffset) - height)
    when (overflow > 0) $ do
      modifyWRef ref (\a -> a { lwScrollOffset = lwScrollOffset a + overflow })
      draw ref

logWidget
  :: forall m. WidgetM m (WRef LogWidget)
logWidget = do
  newWRef $
    LogWidget
    { lwDim = Dimensions 10 10
    , lwContent = []
    , lwPos = ScreenPos 0 0
    , lwVisible = True
    , lwScrollOffset = 0
    }