packages feed

swarm-0.3.0.0: src/Swarm/Game/Scenario/Objective/Presentation/Render.hs

{-# LANGUAGE OverloadedStrings #-}

-- Display logic for Objectives.
module Swarm.Game.Scenario.Objective.Presentation.Render where

import Brick hiding (Direction, Location)
import Brick.Focus
import Brick.Widgets.Center
import Brick.Widgets.List qualified as BL
import Control.Applicative ((<|>))
import Control.Lens hiding (Const, from)
import Data.List.NonEmpty qualified as NE
import Data.Map.Strict qualified as M
import Data.Maybe (listToMaybe)
import Data.Vector qualified as V
import Swarm.Game.Scenario.Objective
import Swarm.Game.Scenario.Objective.Presentation.Model
import Swarm.TUI.Attr
import Swarm.TUI.Model.Name
import Swarm.TUI.View.Util

makeListWidget :: GoalTracking -> BL.List Name GoalEntry
makeListWidget (GoalTracking _announcements categorizedObjs) =
  BL.listMoveTo 1 $ BL.list (GoalWidgets ObjectivesList) (V.fromList objList) 1
 where
  objList = concatMap f $ M.toList categorizedObjs
  f (h, xs) = Header h : map (Goal h) (NE.toList xs)

renderGoalsDisplay :: GoalDisplay -> Widget Name
renderGoalsDisplay gd =
  if hasMultiple
    then
      hBox
        [ leftSide
        , hLimitPercent 70 $ padLeft (Pad 2) goalElaboration
        ]
    else goalElaboration
 where
  hasMultiple = hasMultipleGoals $ gd ^. goalsContent
  lw = _listWidget gd
  fr = _focus gd
  leftSide =
    hLimitPercent 30 $
      padAll 1 $
        vBox
          [ hCenter $ str "Goals"
          , padAll 1 $
              vLimit 10 $
                withFocusRing fr (BL.renderList drawGoalListItem) lw
          ]

  -- Adds very subtle coloring to indicate focus switch
  highlightIfFocused = case (hasMultiple, focusGetCurrent fr) of
    (True, Just (GoalWidgets GoalSummary)) -> withAttr lightCyanAttr
    _ -> id

  -- Note: An extra "padRight" is inserted to account for the vertical scrollbar,
  -- whether or not it appears.
  goalElaboration =
    clickable (GoalWidgets GoalSummary) $
      maybeScroll ModalViewport $
        maybe emptyWidget (padAll 1 . padRight (Pad 1) . highlightIfFocused . singleGoalDetails . snd) $
          BL.listSelectedElement lw

getCompletionIcon :: Objective -> GoalStatus -> Widget Name
getCompletionIcon obj = \case
  Upcoming -> withAttr yellowAttr $ txt " ○  "
  Active -> withAttr cyanAttr $ txt " ○  "
  Failed -> withAttr redAttr $ txt " ●  "
  Completed -> withAttr colorAttr $ txt " ●  "
   where
    colorAttr =
      if obj ^. objectiveHidden
        then magentaAttr
        else greenAttr

drawGoalListItem ::
  Bool ->
  GoalEntry ->
  Widget Name
drawGoalListItem _isSelected e = case e of
  Header gs -> withAttr boldAttr $ str $ show gs
  Goal gs obj -> getCompletionIcon obj gs <+> titleWidget
   where
    textSource = obj ^. objectiveTeaser <|> obj ^. objectiveId <|> listToMaybe (obj ^. objectiveGoal)
    titleWidget = maybe (txt "?") withEllipsis textSource

singleGoalDetails :: GoalEntry -> Widget Name
singleGoalDetails = \case
  Header _gs -> displayParagraphs [" "]
  Goal _gs obj -> displayParagraphs $ obj ^. objectiveGoal