Skip to content

Commit

Permalink
rearrange module content
Browse files Browse the repository at this point in the history
  • Loading branch information
kostmo committed Sep 7, 2024
1 parent 6fcb748 commit ad352a5
Show file tree
Hide file tree
Showing 24 changed files with 470 additions and 374 deletions.
1 change: 1 addition & 0 deletions app/game/Swarm/App.hs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import Swarm.Language.Pretty (prettyText)
import Swarm.Log (LogSource (SystemLog), Severity (..))
import Swarm.TUI.Controller
import Swarm.TUI.Model
import Swarm.TUI.Model.Name
import Swarm.TUI.Model.StateUpdate
import Swarm.TUI.Model.UI (uiAttrMap)
import Swarm.TUI.View
Expand Down
13 changes: 13 additions & 0 deletions src/swarm-topography/Swarm/Game/Universe.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Control.Lens (makeLenses, view)
import Data.Function (on)
import Data.Int (Int32)
import Data.Text (Text)
import Data.Text qualified as T
import Data.Yaml (FromJSON, ToJSON, Value (Object), parseJSON, withText, (.:))
import GHC.Generics (Generic)
import Linear (V2 (..))
Expand Down Expand Up @@ -82,3 +83,15 @@ defaultCosmicLocation = Cosmic DefaultRootSubworld origin

offsetBy :: Cosmic Location -> V2 Int32 -> Cosmic Location
offsetBy loc v = fmap (.+^ v) loc

locationToString :: Location -> String
locationToString (Location x y) =
unwords $ map show [x, y]

renderCoordsString :: Cosmic Location -> String
renderCoordsString (Cosmic sw coords) =
unwords $ locationToString coords : suffix
where
suffix = case sw of
DefaultRootSubworld -> []
SubworldName swName -> ["in", T.unpack swName]
1 change: 1 addition & 0 deletions src/swarm-tui/Swarm/TUI/Controller/EventHandlers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import Swarm.TUI.Controller.EventHandlers.Robot (handleRobotPanelEvent, robotEve
import Swarm.TUI.Controller.EventHandlers.World (worldEventHandlers)
import Swarm.TUI.Model
import Swarm.TUI.Model.Event (SwarmEvent, swarmEvents)
import Swarm.TUI.Model.Name
import Swarm.Util (parens, squote)

-- ~~~~ Note [how Swarm event handlers work]
Expand Down
1 change: 1 addition & 0 deletions src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Frame.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import Swarm.TUI.Controller.UpdateUI
import Swarm.TUI.Controller.Util
import Swarm.TUI.Model
import Swarm.TUI.Model.Achievements (popupAchievement)
import Swarm.TUI.Model.Name
import Swarm.TUI.Model.UI
import System.Clock

Expand Down
1 change: 1 addition & 0 deletions src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import Swarm.TUI.Model
import Swarm.TUI.Model.DebugOption (DebugOption (ToggleCreative, ToggleWorldEditor))
import Swarm.TUI.Model.Dialog.Goal
import Swarm.TUI.Model.Event (MainEvent (..), SwarmEvent (..))
import Swarm.TUI.Model.Name
import Swarm.TUI.Model.UI
import System.Clock (Clock (..), TimeSpec (..), getTime)

Expand Down
1 change: 1 addition & 0 deletions src/swarm-tui/Swarm/TUI/Controller/EventHandlers/REPL.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Swarm.Game.State.Substate
import Swarm.TUI.Controller.Util
import Swarm.TUI.Model
import Swarm.TUI.Model.Event
import Swarm.TUI.Model.Name
import Swarm.TUI.Model.Repl
import Swarm.TUI.Model.UI

Expand Down
1 change: 1 addition & 0 deletions src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Robot.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import Swarm.TUI.Inventory.Sorting (cycleSortDirection, cycleSortOrder)
import Swarm.TUI.List
import Swarm.TUI.Model
import Swarm.TUI.Model.Event
import Swarm.TUI.Model.Name
import Swarm.TUI.Model.UI
import Swarm.TUI.View.Util (generateModal)

Expand Down
1 change: 1 addition & 0 deletions src/swarm-tui/Swarm/TUI/Controller/EventHandlers/World.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Swarm.Language.Syntax.Direction (Direction (..), directionSyntax)
import Swarm.TUI.Controller.Util
import Swarm.TUI.Model
import Swarm.TUI.Model.Event
import Swarm.TUI.Model.Name
import Swarm.TUI.Model.UI

-- | Handle a user input event in the world view panel.
Expand Down
2 changes: 1 addition & 1 deletion src/swarm-tui/Swarm/TUI/Controller/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ import Swarm.TUI.Model (
AppState,
FocusablePanel,
ModalType (..),
Name (..),
gameState,
modalScroll,
uiState,
)
import Swarm.TUI.Model.Name
import Swarm.TUI.Model.Repl (REPLHistItem, REPLPrompt, REPLState, addREPLItem, replHistory, replPromptText, replPromptType)
import Swarm.TUI.Model.UI
import Swarm.TUI.View.Util (generateModal)
Expand Down
2 changes: 1 addition & 1 deletion src/swarm-tui/Swarm/TUI/Editor/Masking.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Swarm.Game.Universe
import Swarm.Game.World.Coords
import Swarm.TUI.Editor.Model
import Swarm.TUI.Editor.Util qualified as EU
import Swarm.TUI.Model.UI
import Swarm.TUI.Model.UI.Gameplay

shouldHideWorldCell :: UIGameplay -> Coords -> Bool
shouldHideWorldCell ui coords =
Expand Down
2 changes: 1 addition & 1 deletion src/swarm-tui/Swarm/TUI/Editor/View.hs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ drawWorldEditor toplevelFocusRing uis =
L.intersperse
"@"
[ EA.renderRectDimensions rectArea
, VU.locationToString upperLeftLoc
, locationToString upperLeftLoc
]
where
upperLeftLoc = coordsToLoc upperLeftCoord
Expand Down
1 change: 0 additions & 1 deletion src/swarm-tui/Swarm/TUI/Model.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ module Swarm.TUI.Model (
-- $uilabel
AppEvent (..),
FocusablePanel (..),
Name (..),

-- ** Web command
WebCommand (..),
Expand Down
177 changes: 144 additions & 33 deletions src/swarm-tui/Swarm/TUI/Model/Dialog/Robot.hs
Original file line number Diff line number Diff line change
@@ -1,50 +1,60 @@
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- A UI-centric model for Structure presentation.
module Swarm.TUI.Model.Dialog.Robot where

import Brick
import Control.Lens hiding (from, (<.>))
import Swarm.Game.Robot
import Data.Maybe (fromMaybe)
import Swarm.Game.Robot.Activity
import Swarm.Game.Robot.Concrete
import Swarm.Game.State.Robot
import Swarm.Game.World.Coords
import Swarm.TUI.View.CellDisplay
import Swarm.TUI.View.Robot

-- import Swarm.TUI.View.Util

import Brick
import Brick.AttrMap
import Brick.Widgets.Border
import Brick.Widgets.Table qualified as BT
import Brick.Widgets.TabularList.Mixed
import Control.Lens hiding (from, (<.>))
import Control.Lens as Lens hiding (Const, from)
import Data.IntMap qualified as IM
import Data.Map qualified as M
import Data.Sequence (Seq)
import Data.Sequence qualified as S
import Data.Set (Set)
import Data.Vector (Vector)
import Data.Vector qualified as V
import GHC.Generics (Generic)
import Linear (V2 (..), distance)
import Swarm.Game.CESK (CESK (..))
import Swarm.Game.Entity as E
import Swarm.Game.Location
import Swarm.Game.Robot
import Swarm.Game.State
import Swarm.Game.Universe
import Swarm.TUI.Model.DebugOption
import Swarm.TUI.Model.Dialog.RobotDisplay
import Swarm.TUI.Model.Name

data RobotsDisplayMode = RobotList | SingleRobotDetails
deriving (Eq, Show, Enum, Bounded)

newtype Widths = Widths
{ robotRowWidths :: [ColWidth]
import Swarm.TUI.Model.UI.Gameplay
import Swarm.TUI.View.Attribute.Attr
import Swarm.Util (applyWhen)
import System.Clock (TimeSpec (..))

data RobotRenderingContext = RobotRenderingContext
{ _mygs :: GameState
, _gameplay :: UIGameplay
, _timing :: UITiming
, _uiDbg :: Set DebugOption
}
deriving (Generic)

data LibRobotRow = LibRobotRow String String String

type LibraryList = MixedTabularList Name LibRobotRow Widths
type LibraryRenderers = MixedRenderers Name LibRobotRow Widths

data RobotDisplay = RobotDisplay
{ _robotsDisplayMode :: RobotsDisplayMode
-- ^ required for maintaining the selection/navigation
-- state among list items
, _lastFocusedRobotId :: Maybe RID
, _libList :: LibraryList
, _libRenderers :: LibraryRenderers
}

makeLenses ''RobotDisplay
makeLenses ''RobotRenderingContext

emptyRobotDisplay :: RobotDisplay
emptyRobotDisplay =
Expand Down Expand Up @@ -100,20 +110,27 @@ wpr :: WidthsPerRow LibRobotRow Widths
wpr = WsPerR $ \(Widths song) e -> case e of
LibRobotRow {} -> song

dc :: ListFocused -> MixedCtxt -> LibRobotRow -> Widget n
dc _ (MxdCtxt _ (MColC (Ix ci))) (LibRobotRow c1 c2 c3) =
dc :: ListFocused -> MixedCtxt -> LibRobotRow -> Widget Name
dc _ (MxdCtxt _ (MColC (Ix ci))) r =
let renderPlainCell s = padRight Max (str s) <+> str " "
in case ci of
0 -> renderPlainCell c1
1 -> renderPlainCell c2
2 -> renderPlainCell c3
0 -> _fName r
1 -> _fAge r
2 -> _fPos r
3 -> _fItems r
4 -> _fStatus r
5 -> _fActns r
6 -> _fCmds r
7 -> _fCycles r
8 -> _fActivity r
9 -> _fLog r
_ -> emptyWidget

libraryEntries :: Seq LibRobotRow
libraryEntries =
let songs =
map
(\n -> LibRobotRow ("foo" ++ show n) "bar" "blah")
(\n -> LibRobotRow (str ("foo" ++ show n)) (str "bar") (str "blah") (str "blah") (str "blah") (str "blah") (str "blah") (str "blah") (str "blah") (str "blah"))
[1 .. 12 :: Int]
in S.fromList songs

Expand All @@ -123,3 +140,97 @@ wprk = WsPerRK $ \(AvlW aW) _ ->
title = max 6 $ (aW * 30) `div` 100
album = aW - artist - title
in Widths {robotRowWidths = fmap ColW [artist, title, album]}

robotsTable :: RobotRenderingContext -> BT.Table Name
robotsTable c =
BT.table $
map (padLeftRight 1) <$> (headers : robotRows)
where
headings =
[ "Name"
, "Age"
, "Pos"
, "Items"
, "Status"
, "Actns"
, "Cmds"
, "Cycles"
, "Activity"
, "Log"
]
headers = withAttr robotAttr . txt <$> applyWhen debugRID ("ID" :) headings
robotRows = mkRobotRow <$> robots
mkRobotRow robot =
applyWhen debugRID (idWidget :) cells
where
cells =
[ nameWidget
, str ageStr
, locWidget
, padRight (Pad 1) (str $ show rInvCount)
, statusWidget
, str $ show $ robot ^. activityCounts . tangibleCommandCount
, -- TODO(#1341): May want to expose the details of this histogram in
-- a per-robot pop-up
str . show . sum . M.elems $ robot ^. activityCounts . commandsHistogram
, str $ show $ robot ^. activityCounts . lifetimeStepCount
, renderDutyCycle (c ^. mygs . temporal) robot
, txt rLog
]

idWidget = str $ show $ robot ^. robotID
nameWidget =
hBox
[ renderDisplay (robot ^. robotDisplay)
, highlightSystem . txt $ " " <> robot ^. robotName
]

highlightSystem = if robot ^. systemRobot then withAttr highlightAttr else id

ageStr
| age < 60 = show age <> "sec"
| age < 3600 = show (age `div` 60) <> "min"
| age < 3600 * 24 = show (age `div` 3600) <> "hour"
| otherwise = show (age `div` 3600 * 24) <> "day"
where
TimeSpec createdAtSec _ = robot ^. robotCreatedAt
TimeSpec nowSec _ = c ^. timing . lastFrameTime
age = nowSec - createdAtSec

rInvCount = sum $ map fst . E.elems $ robot ^. robotEntity . entityInventory
rLog
| robot ^. robotLogUpdated = "x"
| otherwise = " "

locWidget = hBox [worldCell, str $ " " <> locStr]
where
rCoords = fmap locToCoords rLoc
rLoc = robot ^. robotLocation
worldCell =
drawLoc
(c ^. gameplay)
g
rCoords
locStr = renderCoordsString rLoc

statusWidget = case robot ^. machine of
Waiting {} -> txt "waiting"
_
| isActive robot -> withAttr notifAttr $ txt "busy"
| otherwise -> withAttr greenAttr $ txt "idle"

basePos :: Point V2 Double
basePos = realToFrac <$> fromMaybe origin (g ^? baseRobot . robotLocation . planar)
-- Keep the base and non system robot (e.g. no seed)
isRelevant robot = robot ^. robotID == 0 || not (robot ^. systemRobot)
-- Keep the robot that are less than 32 unit away from the base
isNear robot = creative || distance (realToFrac <$> robot ^. robotLocation . planar) basePos < 32
robots :: [Robot]
robots =
filter (\robot -> debugAllRobots || (isRelevant robot && isNear robot))
. IM.elems
$ g ^. robotInfo . robotMap
creative = g ^. creativeMode
debugRID = c ^. uiDbg . Lens.contains ListRobotIDs
debugAllRobots = c ^. uiDbg . Lens.contains ListAllRobots
g = c ^. mygs
48 changes: 48 additions & 0 deletions src/swarm-tui/Swarm/TUI/Model/Dialog/RobotDisplay.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
module Swarm.TUI.Model.Dialog.RobotDisplay where

import Brick
import Brick.Widgets.TabularList.Mixed
import Control.Lens hiding (from, (<.>))
import GHC.Generics (Generic)
import Swarm.Game.Robot
import Swarm.TUI.Model.Name

newtype Widths = Widths
{ robotRowWidths :: [ColWidth]
}
deriving (Generic)

data LibRobotRow = LibRobotRow
{ _fName :: Widget Name
, _fAge :: Widget Name
, _fPos :: Widget Name
, _fItems :: Widget Name
, _fStatus :: Widget Name
, _fActns :: Widget Name
, _fCmds :: Widget Name
, _fCycles :: Widget Name
, _fActivity :: Widget Name
, _fLog :: Widget Name
}

data RobotsDisplayMode = RobotList | SingleRobotDetails
deriving (Eq, Show, Enum, Bounded)

type LibraryList = MixedTabularList Name LibRobotRow Widths
type LibraryRenderers = MixedRenderers Name LibRobotRow Widths

data RobotDisplay = RobotDisplay
{ _robotsDisplayMode :: RobotsDisplayMode
-- ^ required for maintaining the selection/navigation
-- state among list items
, _lastFocusedRobotId :: Maybe RID
, _libList :: LibraryList
, _libRenderers :: LibraryRenderers
}

makeLenses ''RobotDisplay
1 change: 1 addition & 0 deletions src/swarm-tui/Swarm/TUI/Model/KeyBindings.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import Swarm.Language.Pretty (prettyText)
import Swarm.TUI.Controller.EventHandlers
import Swarm.TUI.Model
import Swarm.TUI.Model.Event (SwarmEvent, defaultSwarmBindings, swarmEvents)
import Swarm.TUI.Model.Name

-- See Note [how Swarm event handlers work]

Expand Down
Loading

0 comments on commit ad352a5

Please sign in to comment.