swarm-0.5.0.0: src/Swarm/TUI/View/Objective.hs
{-# LANGUAGE OverloadedStrings #-}
-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Display logic for Objectives.
module Swarm.TUI.View.Objective 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 (intercalate)
import Data.List.NonEmpty qualified as NE
import Data.Map.Strict qualified as M
import Data.Vector qualified as V
import Swarm.Game.Scenario.Objective
import Swarm.Language.Text.Markdown qualified as Markdown
import Swarm.TUI.Model.Goal
import Swarm.TUI.Model.Name
import Swarm.TUI.View.Attribute.Attr
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 = intercalate [Spacer] $ map f $ M.toList categorizedObjs
f (h, xs) = Header h : map (Goal h) (NE.toList xs)
renderGoalsDisplay :: GoalDisplay -> Widget Name
renderGoalsDisplay gd =
if hasMultiple
then
vBox
[ hBox
[ leftSide
, hLimitPercent 70 $ padLeft (Pad 2) goalElaboration
]
, footer
]
else goalElaboration
where
footer = hCenter $ withAttr italicAttr $ txt "NOTE: [Tab] toggles focus between panes"
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
Spacer -> str " "
Header gs -> withAttr boldAttr $ str $ show gs
Goal gs obj -> getCompletionIcon obj gs <+> titleWidget
where
textSource = obj ^. objectiveTeaser <|> obj ^. objectiveId <|> Just (Markdown.docToText $ obj ^. objectiveGoal)
titleWidget = maybe (txt "?") (withEllipsis End) textSource
singleGoalDetails :: GoalEntry -> Widget Name
singleGoalDetails = \case
Goal _gs obj -> drawMarkdown $ obj ^. objectiveGoal
-- Only Goal entries are selectable, so we should never see this:
_ -> emptyWidget