swarm-0.5.0.0: src/Swarm/TUI/View/Attribute/Attr.hs
{-# LANGUAGE OverloadedStrings #-}
-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Rendering attributes (/i.e./ foreground and background colors,
-- styles, /etc./) used by the Swarm TUI.
--
-- We export constants only for those we use in the Haskell code
-- and not those used in the world map, to avoid abusing attributes.
-- For example using the robot attribute to highlight some text.
--
-- The few attributes that we use for drawing the logo are an exception.
module Swarm.TUI.View.Attribute.Attr (
swarmAttrMap,
worldAttributeNames,
worldPrefix,
meterAttributeNames,
toAttrName,
-- ** Terrain attributes
dirtAttr,
grassAttr,
stoneAttr,
waterAttr,
iceAttr,
-- ** Common attributes
entityAttr,
robotAttr,
rockAttr,
plantAttr,
-- ** Swarm TUI Attributes
highlightAttr,
notifAttr,
infoAttr,
boldAttr,
italicAttr,
dimAttr,
magentaAttr,
cyanAttr,
lightCyanAttr,
yellowAttr,
blueAttr,
greenAttr,
redAttr,
defAttr,
customEditFocusedAttr,
) where
import Brick
import Brick.Forms
import Brick.Widgets.Dialog
import Brick.Widgets.Edit qualified as E
import Brick.Widgets.List hiding (reverse)
import Data.Bifunctor (bimap, first)
import Data.Colour.Palette.BrewerSet
import Data.List.NonEmpty (NonEmpty (..))
import Data.List.NonEmpty qualified as NE
import Data.Maybe (fromMaybe)
import Data.Text (unpack)
import Graphics.Vty qualified as V
import Swarm.Game.Display (Attribute (..))
import Swarm.TUI.View.Attribute.Util
toAttrName :: Attribute -> AttrName
toAttrName = \case
ARobot -> robotAttr
AEntity -> entityAttr
AWorld n -> worldPrefix <> attrName (unpack n)
ATerrain n -> terrainPrefix <> attrName (unpack n)
ADefault -> defAttr
-- | A mapping from the defined attribute names to TUI attributes.
swarmAttrMap :: AttrMap
swarmAttrMap =
attrMap
V.defAttr
$ NE.toList activityMeterAttributes
<> NE.toList (NE.map (first getWorldAttrName) worldAttributes)
<> [(waterAttr, V.white `on` V.blue)]
<> terrainAttr
<> [ -- Robot attribute
(robotAttr, fg V.white `V.withStyle` V.bold)
, -- UI rendering attributes
(highlightAttr, fg V.cyan)
, (invalidFormInputAttr, fg V.red)
, (focusedFormInputAttr, V.defAttr)
, (customEditFocusedAttr, V.black `on` V.yellow)
, (listSelectedFocusedAttr, bg V.blue)
, (infoAttr, fg (V.rgbColor @Int 100 100 100))
, (buttonSelectedAttr, bg V.blue)
, (notifAttr, fg V.yellow `V.withStyle` V.bold)
, (dimAttr, V.defAttr `V.withStyle` V.dim)
, (boldAttr, V.defAttr `V.withStyle` V.bold)
, (italicAttr, V.defAttr `V.withStyle` V.italic)
, -- Basic colors
(redAttr, fg V.red)
, (greenAttr, fg V.green)
, (blueAttr, fg V.blue)
, (yellowAttr, fg V.yellow)
, (cyanAttr, fg V.cyan)
, (lightCyanAttr, fg (V.rgbColor @Int 200 255 255))
, (magentaAttr, fg V.magenta)
, -- Default attribute
(defAttr, V.defAttr)
]
worldPrefix :: AttrName
worldPrefix = attrName "world"
-- | We introduce this (module-private) newtype
-- so that we can define the 'entity' attribute
-- separate from the list of other 'worldAttributes',
-- while enforcing the convention that both its attribute
-- name and the rest of 'worldAttributes' be consistently
-- prefixed by 'worldPrefix'.
newtype WorldAttr = WorldAttr
{ getWorldAttrName :: AttrName
}
mkWorldAttr :: String -> WorldAttr
mkWorldAttr = WorldAttr . (worldPrefix <>) . attrName
entity :: (WorldAttr, V.Attr)
entity = (mkWorldAttr "entity", fg V.white)
entityAttr :: AttrName
entityAttr = getWorldAttrName $ fst entity
-- | Colors of entities in the world.
--
-- Also used to color messages, so water is special and excluded.
worldAttributes :: NonEmpty (WorldAttr, V.Attr)
worldAttributes =
entity
:| map
(bimap mkWorldAttr fg)
[ ("device", V.brightYellow)
, ("plant", V.green)
, ("rock", V.rgbColor @Int 80 80 80)
, ("wood", V.rgbColor @Int 139 69 19)
, ("flower", V.rgbColor @Int 200 0 200)
, ("rubber", V.rgbColor @Int 245 224 179)
, ("copper", V.yellow)
, ("copper'", V.rgbColor @Int 78 117 102)
, ("iron", V.rgbColor @Int 97 102 106)
, ("iron'", V.rgbColor @Int 183 65 14)
, ("quartz", V.white)
, ("silver", V.rgbColor @Int 192 192 192)
, ("gold", V.rgbColor @Int 255 215 0)
, ("snow", V.white)
, ("sand", V.rgbColor @Int 194 178 128)
, ("fire", V.brightRed)
, ("red", V.red)
, ("green", V.green)
, ("blue", V.blue)
]
worldAttributeNames :: NonEmpty AttrName
worldAttributeNames = NE.map (getWorldAttrName . fst) worldAttributes
activityMeterPrefix :: AttrName
activityMeterPrefix = attrName "activityMeter"
activityMeterAttributes :: NonEmpty (AttrName, V.Attr)
activityMeterAttributes =
NE.zip indices $ fromMaybe (pure $ bg V.black) $ NE.nonEmpty brewers
where
indices = NE.map ((activityMeterPrefix <>) . attrName . show) $ (0 :: Int) :| [1 ..]
brewers = map bgWithAutoForeground $ reverse $ brewerSet RdYlGn 7
meterAttributeNames :: NonEmpty AttrName
meterAttributeNames = NE.map fst activityMeterAttributes
terrainPrefix :: AttrName
terrainPrefix = attrName "terrain"
terrainAttr :: [(AttrName, V.Attr)]
terrainAttr =
[ (dirtAttr, fg (V.rgbColor @Int 165 42 42))
, (grassAttr, fg (V.rgbColor @Int 0 32 0)) -- dark green
, (stoneAttr, fg (V.rgbColor @Int 32 32 32))
, (iceAttr, bg V.white)
]
-- | The default robot attribute.
robotAttr :: AttrName
robotAttr = attrName "robot"
dirtAttr, grassAttr, stoneAttr, iceAttr, waterAttr, rockAttr, plantAttr :: AttrName
dirtAttr = terrainPrefix <> attrName "dirt"
grassAttr = terrainPrefix <> attrName "grass"
stoneAttr = terrainPrefix <> attrName "stone"
iceAttr = terrainPrefix <> attrName "ice"
waterAttr = worldPrefix <> attrName "water"
rockAttr = worldPrefix <> attrName "rock"
plantAttr = worldPrefix <> attrName "plant"
-- | Some defined attribute names used in the Swarm TUI.
highlightAttr
, notifAttr
, infoAttr
, boldAttr
, italicAttr
, dimAttr
, defAttr ::
AttrName
highlightAttr = attrName "highlight"
notifAttr = attrName "notif"
infoAttr = attrName "info"
boldAttr = attrName "bold"
italicAttr = attrName "italics"
dimAttr = attrName "dim"
defAttr = attrName "def"
customEditFocusedAttr :: AttrName
customEditFocusedAttr = attrName "custom" <> E.editFocusedAttr
-- | Some basic colors used in TUI.
redAttr, greenAttr, blueAttr, yellowAttr, cyanAttr, lightCyanAttr, magentaAttr :: AttrName
redAttr = attrName "red"
greenAttr = attrName "green"
blueAttr = attrName "blue"
yellowAttr = attrName "yellow"
cyanAttr = attrName "cyan"
lightCyanAttr = attrName "lightCyan"
magentaAttr = attrName "magenta"