Skip to content

Commit

Permalink
navigable table
Browse files Browse the repository at this point in the history
  • Loading branch information
kostmo committed Sep 14, 2024
1 parent 7b99e72 commit e3d0920
Show file tree
Hide file tree
Showing 30 changed files with 816 additions and 305 deletions.
2 changes: 2 additions & 0 deletions .hlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
- {name: Data.List.head, within: []}
- {name: Prelude.head, within: [Swarm.Web.Tournament.Database.Query]}
- {name: Prelude.tail, within: []}
- {name: Prelude.maximum, within: [Swarm.Util]}
- {name: Prelude.minimum, within: []}
- {name: Prelude.!!, within: [Swarm.Util.indexWrapNonEmpty, TestEval]}
- {name: undefined, within: [Swarm.Language.Key, TestUtil]}
- {name: fromJust, within: []}
Expand Down
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
4 changes: 2 additions & 2 deletions src/swarm-doc/Swarm/Doc/Wiki/Cheatsheet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import Swarm.Language.Syntax (Const (..))
import Swarm.Language.Syntax qualified as Syntax
import Swarm.Language.Text.Markdown as Markdown (docToMark)
import Swarm.Language.Typecheck (inferConst)
import Swarm.Util (showT)
import Swarm.Util (maximum0, showT)

-- * Types

Expand Down Expand Up @@ -99,7 +99,7 @@ listToRow mw xs = wrap '|' . T.intercalate "|" $ zipWith format mw xs
format w x = wrap ' ' x <> T.replicate (w - T.length x) " "

maxWidths :: [[Text]] -> [Int]
maxWidths = map (maximum . map T.length) . transpose
maxWidths = map (maximum0 . map T.length) . transpose

-- ** COMMANDS

Expand Down
15 changes: 15 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,17 @@ defaultCosmicLocation = Cosmic DefaultRootSubworld origin

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

-- ** Rendering

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]
23 changes: 20 additions & 3 deletions src/swarm-tui/Swarm/TUI/Controller.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ module Swarm.TUI.Controller (
) where

-- See Note [liftA2 re-export from Prelude]
import Prelude hiding (Applicative (..))

import Brick hiding (Direction, Location)
import Brick.Focus
Expand All @@ -36,10 +35,11 @@ import Brick.Widgets.Dialog
import Brick.Widgets.Edit (Editor, applyEdit, handleEditorEvent)
import Brick.Widgets.List (handleListEvent)
import Brick.Widgets.List qualified as BL
import Brick.Widgets.TabularList.Mixed
import Control.Applicative (pure)
import Control.Category ((>>>))
import Control.Lens as Lens
import Control.Monad (unless, void, when)
import Control.Monad (forM_, unless, void, when)
import Control.Monad.Extra (whenJust)
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.State (MonadState, execState)
Expand Down Expand Up @@ -87,7 +87,7 @@ import Swarm.Language.Value (Value (VKey), envTypes)
import Swarm.Log
import Swarm.TUI.Controller.EventHandlers
import Swarm.TUI.Controller.SaveScenario (saveScenarioInfoOnQuit)
import Swarm.TUI.Controller.UpdateUI (updateAndRedrawUI)
import Swarm.TUI.Controller.UpdateUI
import Swarm.TUI.Controller.Util
import Swarm.TUI.Editor.Controller qualified as EC
import Swarm.TUI.Editor.Model
Expand All @@ -101,7 +101,10 @@ import Swarm.TUI.Model.Name
import Swarm.TUI.Model.Repl
import Swarm.TUI.Model.StateUpdate
import Swarm.TUI.Model.UI
import Swarm.TUI.View.Robot (getList)
import Swarm.TUI.View.Robot.Type
import Swarm.Util hiding (both, (<<.=))
import Prelude hiding (Applicative (..))

-- ~~~~ Note [liftA2 re-export from Prelude]
--
Expand Down Expand Up @@ -418,6 +421,20 @@ handleModalEvent = \case
refreshList $ uiState . uiGameplay . uiDialogs . uiStructure . structurePanelListWidget
StructureSummary -> handleInfoPanelEvent modalScroll (VtyEvent ev)
_ -> handleInfoPanelEvent modalScroll (VtyEvent ev)
Just RobotsModal -> Brick.zoom (uiState . uiGameplay . uiDialogs . uiRobot) $ case ev of
V.EvKey (V.KChar '\t') [] -> robotDetailsFocus %= focusNext
_ -> do
foc <- use robotDetailsFocus
case focusGetCurrent foc of
(Just (RobotsListDialog (SingleRobotDetails RobotLogPane))) ->
Brick.zoom (robotListContent . robotDetailsPaneState . logsList) $ handleListEvent ev
_ -> do
Brick.zoom (robotListContent . robotsListWidget) $
handleMixedListEvent ev

-- Ensure list widget content is updated immediately
widget <- use $ robotListContent . robotsListWidget
forM_ (BL.listSelectedElement $ getList widget) $ updateRobotDetailsPane . snd
_ -> handleInfoPanelEvent modalScroll (VtyEvent ev)
where
refreshGoalList lw = nestEventM' lw $ handleListEventWithSeparators ev shouldSkipSelection
Expand Down
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
47 changes: 43 additions & 4 deletions src/swarm-tui/Swarm/TUI/Controller/UpdateUI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,28 @@
module Swarm.TUI.Controller.UpdateUI (
updateUI,
updateAndRedrawUI,
updateRobotDetailsPane,
) where

import Brick hiding (Direction, Location)
import Brick.Focus

-- See Note [liftA2 re-export from Prelude]
import Brick hiding (Direction, Location, on)
import Brick.Focus
import Brick.Widgets.List qualified as BL
import Control.Applicative (liftA2, pure)
import Control.Lens as Lens
import Control.Monad (unless, when)
import Control.Monad (forM_, unless, when)
import Control.Monad.IO.Class (liftIO)
import Data.Foldable (toList)
import Data.Function (on)
import Data.List.Extra (enumerate)
import Data.Map qualified as M
import Data.Maybe (isNothing)
import Data.String (fromString)
import Data.Text qualified as T
import Data.Vector qualified as V
import Swarm.Game.Entity hiding (empty)
import Swarm.Game.Robot
import Swarm.Game.Robot.Activity
import Swarm.Game.Robot.Concrete
import Swarm.Game.State
import Swarm.Game.State.Landscape
Expand All @@ -43,6 +47,9 @@ import Swarm.TUI.Model.Name
import Swarm.TUI.Model.Repl
import Swarm.TUI.Model.UI
import Swarm.TUI.View.Objective qualified as GR
import Swarm.TUI.View.Robot
import Swarm.TUI.View.Robot.Type
import Swarm.Util (applyJust)
import Witch (into)
import Prelude hiding (Applicative (..))

Expand Down Expand Up @@ -165,6 +172,8 @@ updateUI = do

newPopups <- generateNotificationPopups

doRobotListUpdate g

let redraw =
g ^. needsRedraw
|| inventoryUpdated
Expand All @@ -174,6 +183,36 @@ updateUI = do
|| newPopups
pure redraw

doRobotListUpdate :: GameState -> EventM Name AppState ()
doRobotListUpdate g = do
gp <- use $ uiState . uiGameplay
dOps <- use $ uiState . uiDebugOptions

let rd =
mkRobotDisplay $
RobotRenderingContext
{ _mygs = g
, _gameplay = gp
, _timing = gp ^. uiTiming
, _uiDbg = dOps
}
oldList = getList $ gp ^. uiDialogs . uiRobot . robotListContent . robotsListWidget
maybeOldSelected = snd <$> BL.listSelectedElement oldList

maybeModificationFunc =
updateList . BL.listFindBy . ((==) `on` view (rob . robotID)) <$> maybeOldSelected

uiState . uiGameplay . uiDialogs . uiRobot . robotListContent . robotsListWidget .= applyJust maybeModificationFunc rd

Brick.zoom (uiState . uiGameplay . uiDialogs . uiRobot) $
forM_ maybeOldSelected updateRobotDetailsPane

updateRobotDetailsPane :: RobotWidgetRow -> EventM Name RobotDisplay ()
updateRobotDetailsPane robotPayload =
Brick.zoom robotListContent $ do
robotDetailsPaneState . cmdHistogramList . BL.listElementsL .= V.fromList (M.toList (robotPayload ^. rob . activityCounts . commandsHistogram))
robotDetailsPaneState . logsList . BL.listElementsL .= robotPayload ^. rob . robotLog

-- | Either pops up the updated Goals modal
-- or pops up the Congratulations (Win) modal, or pops
-- up the Condolences (Lose) modal.
Expand Down
3 changes: 1 addition & 2 deletions src/swarm-tui/Swarm/TUI/Controller/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,12 @@ import Swarm.Language.Capability (Capability (CDebug))
import Swarm.Language.Syntax hiding (Key)
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
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
13 changes: 13 additions & 0 deletions src/swarm-tui/Swarm/TUI/Model/Name.hs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ data Button
| NextButton
deriving (Eq, Ord, Show, Read, Bounded, Enum)

-- | Robot details
data RobotDetailSubpane
= RobotLogPane
| RobotCommandHistogramPane
deriving (Eq, Ord, Show, Read, Bounded, Enum)

data RobotsDisplayMode
= RobotList
| SingleRobotDetails RobotDetailSubpane
deriving (Eq, Ord, Show, Read)

-- | 'Name' represents names to uniquely identify various components
-- of the UI, such as forms, panels, caches, extents, lists, and buttons.
data Name
Expand Down Expand Up @@ -106,6 +117,8 @@ data Name
StructureWidgets StructureWidget
| -- | The list of scenario choices.
ScenarioList
| -- | The robots list
RobotsListDialog RobotsDisplayMode
| -- | The scrollable viewport for the info panel.
InfoViewport
| -- | The scrollable viewport for any modal dialog.
Expand Down
Loading

0 comments on commit e3d0920

Please sign in to comment.