From 8e74d7370e41fd301b22350186b42f283ee88c93 Mon Sep 17 00:00:00 2001 From: Karl Ostmo Date: Thu, 5 Sep 2024 14:17:44 -0700 Subject: [PATCH 1/3] Group modal dialog state into a record --- src/swarm-tui/Swarm/TUI/Controller.hs | 32 +++++------ .../TUI/Controller/EventHandlers/Main.hs | 6 +-- .../TUI/Controller/EventHandlers/Robot.hs | 2 +- .../Swarm/TUI/Controller/UpdateUI.hs | 10 ++-- src/swarm-tui/Swarm/TUI/Controller/Util.hs | 6 +-- src/swarm-tui/Swarm/TUI/Model/Achievements.hs | 2 +- .../Swarm/TUI/Model/{ => Dialog}/Goal.hs | 2 +- .../Swarm/TUI/Model/{ => Dialog}/Popup.hs | 2 +- .../Swarm/TUI/Model/{ => Dialog}/Structure.hs | 2 +- src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs | 8 +-- src/swarm-tui/Swarm/TUI/Model/UI.hs | 54 ++++++++++++------- src/swarm-tui/Swarm/TUI/View.hs | 12 ++--- src/swarm-tui/Swarm/TUI/View/Objective.hs | 2 +- src/swarm-tui/Swarm/TUI/View/Popup.hs | 2 +- src/swarm-tui/Swarm/TUI/View/Structure.hs | 2 +- src/swarm-web/Swarm/Web.hs | 4 +- swarm.cabal | 6 +-- 17 files changed, 85 insertions(+), 69 deletions(-) rename src/swarm-tui/Swarm/TUI/Model/{ => Dialog}/Goal.hs (98%) rename src/swarm-tui/Swarm/TUI/Model/{ => Dialog}/Popup.hs (98%) rename src/swarm-tui/Swarm/TUI/Model/{ => Dialog}/Structure.hs (95%) diff --git a/src/swarm-tui/Swarm/TUI/Controller.hs b/src/swarm-tui/Swarm/TUI/Controller.hs index a8476ec71..8dce913f3 100644 --- a/src/swarm-tui/Swarm/TUI/Controller.hs +++ b/src/swarm-tui/Swarm/TUI/Controller.hs @@ -96,12 +96,12 @@ import Swarm.TUI.Launch.Model import Swarm.TUI.Launch.Prep (prepareLaunchDialog) import Swarm.TUI.List import Swarm.TUI.Model -import Swarm.TUI.Model.Goal +import Swarm.TUI.Model.Dialog.Goal +import Swarm.TUI.Model.Dialog.Popup (progressPopups) +import Swarm.TUI.Model.Dialog.Structure import Swarm.TUI.Model.Name -import Swarm.TUI.Model.Popup (progressPopups) import Swarm.TUI.Model.Repl import Swarm.TUI.Model.StateUpdate -import Swarm.TUI.Model.Structure import Swarm.TUI.Model.UI import Swarm.Util hiding (both, (<<.=)) @@ -294,14 +294,14 @@ handleMainEvent forceRedraw ev = do Web (RunWebCode e r) -> runBaseWebCode e r UpstreamVersion _ -> error "version event should be handled by top-level handler" VtyEvent (V.EvResize _ _) -> invalidateCache - EscapeKey | Just m <- s ^. uiState . uiGameplay . uiModal -> closeModal m + EscapeKey | Just m <- s ^. uiState . uiGameplay . uiDialogs . uiModal -> closeModal m -- Pass to key handler (allows users to configure bindings) -- See Note [how Swarm event handlers work] VtyEvent (V.EvKey k m) | isJust (B.lookupVtyEvent k m keyHandler) -> void $ B.handleKey keyHandler k m -- pass keys on to modal event handler if a modal is open VtyEvent vev - | isJust (s ^. uiState . uiGameplay . uiModal) -> handleModalEvent vev + | isJust (s ^. uiState . uiGameplay . uiDialogs . uiModal) -> handleModalEvent vev MouseDown (TerrainListItem pos) V.BLeft _ _ -> uiState . uiGameplay . uiWorldEditor . terrainList %= BL.listMoveTo pos MouseDown (EntityPaintListItem pos) V.BLeft _ _ -> @@ -367,7 +367,7 @@ handleMainEvent forceRedraw ev = do closeModal :: Modal -> EventM Name AppState () closeModal m = do safeAutoUnpause - uiState . uiGameplay . uiModal .= Nothing + uiState . uiGameplay . uiDialogs . uiModal .= Nothing -- message modal is not autopaused, so update notifications when leaving it when ((m ^. modalType) == MessagesModal) $ do t <- use $ gameState . temporal . ticks @@ -377,7 +377,7 @@ closeModal m = do handleModalEvent :: V.Event -> EventM Name AppState () handleModalEvent = \case V.EvKey V.KEnter [] -> do - mdialog <- preuse $ uiState . uiGameplay . uiModal . _Just . modalDialog + mdialog <- preuse $ uiState . uiGameplay . uiDialogs . uiModal . _Just . modalDialog toggleModal QuitModal case dialogSelection =<< mdialog of Just (Button QuitButton, _) -> quitGame @@ -391,33 +391,33 @@ handleModalEvent = \case startGame siPair Nothing _ -> return () ev -> do - Brick.zoom (uiState . uiGameplay . uiModal . _Just . modalDialog) (handleDialogEvent ev) - modal <- preuse $ uiState . uiGameplay . uiModal . _Just . modalType + Brick.zoom (uiState . uiGameplay . uiDialogs . uiModal . _Just . modalDialog) (handleDialogEvent ev) + modal <- preuse $ uiState . uiGameplay . uiDialogs . uiModal . _Just . modalType case modal of Just TerrainPaletteModal -> refreshList $ uiState . uiGameplay . uiWorldEditor . terrainList Just EntityPaletteModal -> do refreshList $ uiState . uiGameplay . uiWorldEditor . entityPaintList Just GoalModal -> case ev of - V.EvKey (V.KChar '\t') [] -> uiState . uiGameplay . uiGoal . focus %= focusNext + V.EvKey (V.KChar '\t') [] -> uiState . uiGameplay . uiDialogs . uiGoal . focus %= focusNext _ -> do - focused <- use $ uiState . uiGameplay . uiGoal . focus + focused <- use $ uiState . uiGameplay . uiDialogs . uiGoal . focus case focusGetCurrent focused of Just (GoalWidgets w) -> case w of ObjectivesList -> do - lw <- use $ uiState . uiGameplay . uiGoal . listWidget + lw <- use $ uiState . uiGameplay . uiDialogs . uiGoal . listWidget newList <- refreshGoalList lw - uiState . uiGameplay . uiGoal . listWidget .= newList + uiState . uiGameplay . uiDialogs . uiGoal . listWidget .= newList GoalSummary -> handleInfoPanelEvent modalScroll (VtyEvent ev) _ -> handleInfoPanelEvent modalScroll (VtyEvent ev) Just StructuresModal -> case ev of - V.EvKey (V.KChar '\t') [] -> uiState . uiGameplay . uiStructure . structurePanelFocus %= focusNext + V.EvKey (V.KChar '\t') [] -> uiState . uiGameplay . uiDialogs . uiStructure . structurePanelFocus %= focusNext _ -> do - focused <- use $ uiState . uiGameplay . uiStructure . structurePanelFocus + focused <- use $ uiState . uiGameplay . uiDialogs . uiStructure . structurePanelFocus case focusGetCurrent focused of Just (StructureWidgets w) -> case w of StructuresList -> - refreshList $ uiState . uiGameplay . uiStructure . structurePanelListWidget + refreshList $ uiState . uiGameplay . uiDialogs . uiStructure . structurePanelListWidget StructureSummary -> handleInfoPanelEvent modalScroll (VtyEvent ev) _ -> handleInfoPanelEvent modalScroll (VtyEvent ev) _ -> handleInfoPanelEvent modalScroll (VtyEvent ev) diff --git a/src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Main.hs b/src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Main.hs index b38006f2d..7bf59d637 100644 --- a/src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Main.hs +++ b/src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Main.hs @@ -24,8 +24,8 @@ import Swarm.TUI.Controller.Util import Swarm.TUI.Editor.Model (isWorldEditorEnabled, worldOverdraw) 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.Goal import Swarm.TUI.Model.UI import System.Clock (Clock (..), TimeSpec (..), getTime) @@ -88,7 +88,7 @@ toggleMessagesModal = do viewGoal :: EventM Name AppState () viewGoal = do s <- get - if hasAnythingToShow $ s ^. uiState . uiGameplay . uiGoal . goalsContent + if hasAnythingToShow $ s ^. uiState . uiGameplay . uiDialogs . uiGoal . goalsContent then toggleModal GoalModal else continueWithoutRedraw @@ -144,7 +144,7 @@ toggleREPLVisibility = do isRunning :: EventM Name AppState Bool isRunning = do - mt <- preuse $ uiState . uiGameplay . uiModal . _Just . modalType + mt <- preuse $ uiState . uiGameplay . uiDialogs . uiModal . _Just . modalType return $ maybe True isRunningModal mt whenRunning :: EventM Name AppState () -> EventM Name AppState () diff --git a/src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Robot.hs b/src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Robot.hs index 542346f76..b2a0bcefb 100644 --- a/src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Robot.hs +++ b/src/swarm-tui/Swarm/TUI/Controller/EventHandlers/Robot.hs @@ -69,7 +69,7 @@ showEntityDescription = gets focusedEntity >>= maybe continueWithoutRedraw descr descriptionModal e = do s <- get resetViewport modalScroll - uiState . uiGameplay . uiModal ?= generateModal s (DescriptionModal e) + uiState . uiGameplay . uiDialogs . uiModal ?= generateModal s (DescriptionModal e) -- | Attempt to make an entity selected from the inventory, if the -- base is not currently busy. diff --git a/src/swarm-tui/Swarm/TUI/Controller/UpdateUI.hs b/src/swarm-tui/Swarm/TUI/Controller/UpdateUI.hs index 5083e1d5b..d9a22e9b6 100644 --- a/src/swarm-tui/Swarm/TUI/Controller/UpdateUI.hs +++ b/src/swarm-tui/Swarm/TUI/Controller/UpdateUI.hs @@ -37,9 +37,9 @@ import Swarm.TUI.Controller.SaveScenario (saveScenarioInfoOnFinishNocheat) import Swarm.TUI.Controller.Util import Swarm.TUI.Model import Swarm.TUI.Model.DebugOption (DebugOption (..)) -import Swarm.TUI.Model.Goal +import Swarm.TUI.Model.Dialog.Goal +import Swarm.TUI.Model.Dialog.Popup (Popup (..), addPopup) import Swarm.TUI.Model.Name -import Swarm.TUI.Model.Popup (Popup (..), addPopup) import Swarm.TUI.Model.Repl import Swarm.TUI.Model.UI import Swarm.TUI.View.Objective qualified as GR @@ -188,7 +188,7 @@ updateUI = do -- * shows the player more "optional" goals they can continue to pursue doGoalUpdates :: EventM Name AppState Bool doGoalUpdates = do - curGoal <- use (uiState . uiGameplay . uiGoal . goalsContent) + curGoal <- use (uiState . uiGameplay . uiDialogs . uiGoal . goalsContent) curWinCondition <- use (gameState . winCondition) announcementsSeq <- use (gameState . messageInfo . announcementQueue) let announcementsList = toList announcementsSeq @@ -218,7 +218,7 @@ doGoalUpdates = do return True WinConditions _ oc -> do showHiddenGoals <- use $ uiState . uiDebugOptions . Lens.contains ShowHiddenGoals - currentModal <- preuse $ uiState . uiGameplay . uiModal . _Just . modalType + currentModal <- preuse $ uiState . uiGameplay . uiDialogs . uiModal . _Just . modalType let newGoalTracking = GoalTracking announcementsList $ constructGoalMap showHiddenGoals oc -- The "uiGoal" field is initialized with empty members, so we know that -- this will be the first time showing it if it will be nonempty after previously @@ -232,7 +232,7 @@ doGoalUpdates = do when (goalWasUpdated && not isEnding) $ do -- The "uiGoal" field is necessary at least to "persist" the data that is needed -- if the player chooses to later "recall" the goals dialog with CTRL+g. - uiState . uiGameplay . uiGoal .= goalDisplay newGoalTracking + uiState . uiGameplay . uiDialogs . uiGoal .= goalDisplay newGoalTracking -- This clears the "flag" that indicate that the goals dialog needs to be -- automatically popped up. diff --git a/src/swarm-tui/Swarm/TUI/Controller/Util.hs b/src/swarm-tui/Swarm/TUI/Controller/Util.hs index 20713716e..dff5581f9 100644 --- a/src/swarm-tui/Swarm/TUI/Controller/Util.hs +++ b/src/swarm-tui/Swarm/TUI/Controller/Util.hs @@ -76,7 +76,7 @@ openModal mt = do resetViewport modalScroll newModal <- gets $ flip generateModal mt ensurePause - uiState . uiGameplay . uiModal ?= newModal + uiState . uiGameplay . uiDialogs . uiModal ?= newModal -- Beep case mt of ScenarioEndModal _ -> do @@ -121,10 +121,10 @@ safeAutoUnpause = do toggleModal :: ModalType -> EventM Name AppState () toggleModal mt = do - modal <- use $ uiState . uiGameplay . uiModal + modal <- use $ uiState . uiGameplay . uiDialogs . uiModal case modal of Nothing -> openModal mt - Just _ -> uiState . uiGameplay . uiModal .= Nothing >> safeAutoUnpause + Just _ -> uiState . uiGameplay . uiDialogs . uiModal .= Nothing >> safeAutoUnpause setFocus :: FocusablePanel -> EventM Name AppState () setFocus name = uiState . uiGameplay . uiFocusRing %= focusSetCurrent (FocusablePanel name) diff --git a/src/swarm-tui/Swarm/TUI/Model/Achievements.hs b/src/swarm-tui/Swarm/TUI/Model/Achievements.hs index 60b895946..c6d0b8015 100644 --- a/src/swarm-tui/Swarm/TUI/Model/Achievements.hs +++ b/src/swarm-tui/Swarm/TUI/Model/Achievements.hs @@ -19,7 +19,7 @@ import Swarm.Game.Achievement.Attainment import Swarm.Game.Achievement.Definitions import Swarm.Game.Achievement.Persistence import Swarm.TUI.Model -import Swarm.TUI.Model.Popup (Popup (AchievementPopup), addPopup) +import Swarm.TUI.Model.Dialog.Popup (Popup (AchievementPopup), addPopup) import Swarm.TUI.Model.UI attainAchievement :: (MonadIO m, MonadState AppState m) => CategorizedAchievement -> m () diff --git a/src/swarm-tui/Swarm/TUI/Model/Goal.hs b/src/swarm-tui/Swarm/TUI/Model/Dialog/Goal.hs similarity index 98% rename from src/swarm-tui/Swarm/TUI/Model/Goal.hs rename to src/swarm-tui/Swarm/TUI/Model/Dialog/Goal.hs index bce891ff5..c02ff33ea 100644 --- a/src/swarm-tui/Swarm/TUI/Model/Goal.hs +++ b/src/swarm-tui/Swarm/TUI/Model/Dialog/Goal.hs @@ -5,7 +5,7 @@ -- SPDX-License-Identifier: BSD-3-Clause -- -- A UI-centric model for Objective presentation. -module Swarm.TUI.Model.Goal where +module Swarm.TUI.Model.Dialog.Goal where import Brick.Focus import Brick.Widgets.List qualified as BL diff --git a/src/swarm-tui/Swarm/TUI/Model/Popup.hs b/src/swarm-tui/Swarm/TUI/Model/Dialog/Popup.hs similarity index 98% rename from src/swarm-tui/Swarm/TUI/Model/Popup.hs rename to src/swarm-tui/Swarm/TUI/Model/Dialog/Popup.hs index 4f0666ba4..15ee84d52 100644 --- a/src/swarm-tui/Swarm/TUI/Model/Popup.hs +++ b/src/swarm-tui/Swarm/TUI/Model/Dialog/Popup.hs @@ -1,7 +1,7 @@ {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE TemplateHaskell #-} -module Swarm.TUI.Model.Popup ( +module Swarm.TUI.Model.Dialog.Popup ( -- * Popup types Popup (..), diff --git a/src/swarm-tui/Swarm/TUI/Model/Structure.hs b/src/swarm-tui/Swarm/TUI/Model/Dialog/Structure.hs similarity index 95% rename from src/swarm-tui/Swarm/TUI/Model/Structure.hs rename to src/swarm-tui/Swarm/TUI/Model/Dialog/Structure.hs index 73a8c23d5..6635524ee 100644 --- a/src/swarm-tui/Swarm/TUI/Model/Structure.hs +++ b/src/swarm-tui/Swarm/TUI/Model/Dialog/Structure.hs @@ -5,7 +5,7 @@ -- SPDX-License-Identifier: BSD-3-Clause -- -- A UI-centric model for Structure presentation. -module Swarm.TUI.Model.Structure where +module Swarm.TUI.Model.Dialog.Structure where import Brick.Focus import Brick.Widgets.List qualified as BL diff --git a/src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs b/src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs index ab6c9f493..ca088b1ea 100644 --- a/src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs +++ b/src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs @@ -82,11 +82,11 @@ import Swarm.TUI.Launch.Model (toSerializableParams) import Swarm.TUI.Model import Swarm.TUI.Model.Achievements import Swarm.TUI.Model.DebugOption (DebugOption (LoadTestingScenarios)) -import Swarm.TUI.Model.Goal (emptyGoalDisplay) +import Swarm.TUI.Model.Dialog.Goal (emptyGoalDisplay) +import Swarm.TUI.Model.Dialog.Structure import Swarm.TUI.Model.KeyBindings import Swarm.TUI.Model.Name import Swarm.TUI.Model.Repl -import Swarm.TUI.Model.Structure import Swarm.TUI.Model.UI import Swarm.TUI.View.Attribute.Attr (getWorldAttrName, swarmAttrMap) import Swarm.TUI.View.Attribute.CustomStyling (toAttrPair) @@ -257,7 +257,7 @@ scenarioToUIState isAutoplaying siPair@(scenario, _) gs u = do fst siPair ^. scenarioLandscape . scenarioAttrs ) swarmAttrMap - & uiGameplay . uiGoal .~ emptyGoalDisplay + & uiGameplay . uiDialogs . uiGoal .~ emptyGoalDisplay & uiGameplay . uiIsAutoPlay .~ isAutoplaying & uiGameplay . uiFocusRing .~ initFocusRing & uiGameplay . uiInventory . uiInventorySearch .~ Nothing @@ -271,7 +271,7 @@ scenarioToUIState isAutoplaying siPair@(scenario, _) gs u = do & uiGameplay . uiTiming . lastFrameTime .~ curTime & uiGameplay . uiWorldEditor . EM.entityPaintList %~ BL.listReplace entityList Nothing & uiGameplay . uiWorldEditor . EM.editingBounds . EM.boundsRect %~ setNewBounds - & uiGameplay . uiStructure + & uiGameplay . uiDialogs . uiStructure .~ StructureDisplay (SR.makeListWidget . M.elems $ gs ^. discovery . structureRecognition . automatons . originalStructureDefinitions) (focusSetCurrent (StructureWidgets StructuresList) $ focusRing $ map StructureWidgets enumerate) diff --git a/src/swarm-tui/Swarm/TUI/Model/UI.hs b/src/swarm-tui/Swarm/TUI/Model/UI.hs index 26faf7cda..e0a07f58e 100644 --- a/src/swarm-tui/Swarm/TUI/Model/UI.hs +++ b/src/swarm-tui/Swarm/TUI/Model/UI.hs @@ -31,6 +31,7 @@ module Swarm.TUI.Model.UI ( uiModal, uiGoal, uiStructure, + uiDialogs, uiIsAutoPlay, uiAchievements, lgTicksPerSecond, @@ -88,12 +89,12 @@ import Swarm.TUI.Inventory.Sorting import Swarm.TUI.Launch.Model import Swarm.TUI.Launch.Prep import Swarm.TUI.Model.DebugOption (DebugOption) -import Swarm.TUI.Model.Goal +import Swarm.TUI.Model.Dialog.Goal +import Swarm.TUI.Model.Dialog.Popup +import Swarm.TUI.Model.Dialog.Structure import Swarm.TUI.Model.Menu import Swarm.TUI.Model.Name -import Swarm.TUI.Model.Popup import Swarm.TUI.Model.Repl -import Swarm.TUI.Model.Structure import Swarm.TUI.View.Attribute.Attr (swarmAttrMap) import Swarm.Util import Swarm.Util.Lens (makeLensesExcluding, makeLensesNoSigs) @@ -194,6 +195,28 @@ uiShowZero :: Lens' UIInventory Bool -- | Whether the Inventory ui panel should update uiInventoryShouldUpdate :: Lens' UIInventory Bool +-- | State that backs various modal dialogs +data UIDialogs = UIDialogs + { _uiModal :: Maybe Modal + , _uiGoal :: GoalDisplay + , _uiStructure :: StructureDisplay + } + +-- * Lenses for UIDialogs + +makeLensesNoSigs ''UIDialogs + +-- | When this is 'Just', it represents a modal to be displayed on +-- top of the UI, e.g. for the Help screen. +uiModal :: Lens' UIDialogs (Maybe Modal) + +-- | Status of the scenario goal: whether there is one, and whether it +-- has been displayed to the user initially. +uiGoal :: Lens' UIDialogs GoalDisplay + +-- | Definition and status of a recognizable structure +uiStructure :: Lens' UIDialogs StructureDisplay + -- | The main record holding the gameplay UI state. For access to the fields, -- see the lenses below. data UIGameplay = UIGameplay @@ -203,9 +226,7 @@ data UIGameplay = UIGameplay , _uiREPL :: REPLState , _uiInventory :: UIInventory , _uiScrollToEnd :: Bool - , _uiModal :: Maybe Modal - , _uiGoal :: GoalDisplay - , _uiStructure :: StructureDisplay + , _uiDialogs :: UIDialogs , _uiIsAutoPlay :: Bool , _uiShowREPL :: Bool , _uiShowDebug :: Bool @@ -241,16 +262,8 @@ uiREPL :: Lens' UIGameplay REPLState -- (used when a new log message is appended). uiScrollToEnd :: Lens' UIGameplay Bool --- | When this is 'Just', it represents a modal to be displayed on --- top of the UI, e.g. for the Help screen. -uiModal :: Lens' UIGameplay (Maybe Modal) - --- | Status of the scenario goal: whether there is one, and whether it --- has been displayed to the user initially. -uiGoal :: Lens' UIGameplay GoalDisplay - --- | Definition and status of a recognizable structure -uiStructure :: Lens' UIGameplay StructureDisplay +-- | State that backs various modal dialogs +uiDialogs :: Lens' UIGameplay UIDialogs -- | When running with @--autoplay@, suppress the goal dialogs. -- @@ -379,9 +392,12 @@ initUIState speedFactor showMainMenu debug = do , _uiInventoryShouldUpdate = False } , _uiScrollToEnd = False - , _uiModal = Nothing - , _uiGoal = emptyGoalDisplay - , _uiStructure = emptyStructureDisplay + , _uiDialogs = + UIDialogs + { _uiModal = Nothing + , _uiGoal = emptyGoalDisplay + , _uiStructure = emptyStructureDisplay + } , _uiIsAutoPlay = False , _uiTiming = UITiming diff --git a/src/swarm-tui/Swarm/TUI/View.hs b/src/swarm-tui/Swarm/TUI/View.hs index 515c64c32..20f51a887 100644 --- a/src/swarm-tui/Swarm/TUI/View.hs +++ b/src/swarm-tui/Swarm/TUI/View.hs @@ -134,8 +134,8 @@ import Swarm.TUI.Launch.Model import Swarm.TUI.Launch.View import Swarm.TUI.Model import Swarm.TUI.Model.DebugOption (DebugOption (..)) +import Swarm.TUI.Model.Dialog.Goal (goalsContent, hasAnythingToShow) import Swarm.TUI.Model.Event qualified as SE -import Swarm.TUI.Model.Goal (goalsContent, hasAnythingToShow) import Swarm.TUI.Model.KeyBindings (handlerNameKeysDescription) import Swarm.TUI.Model.Repl import Swarm.TUI.Model.UI @@ -613,13 +613,13 @@ replHeight = 10 -- | Hide the cursor when a modal is set chooseCursor :: AppState -> [CursorLocation n] -> Maybe (CursorLocation n) -chooseCursor s locs = case s ^. uiState . uiGameplay . uiModal of +chooseCursor s locs = case s ^. uiState . uiGameplay . uiDialogs . uiModal of Nothing -> showFirstCursor s locs Just _ -> Nothing -- | Draw a dialog window, if one should be displayed right now. drawDialog :: AppState -> Widget Name -drawDialog s = case s ^. uiState . uiGameplay . uiModal of +drawDialog s = case s ^. uiState . uiGameplay . uiDialogs . uiModal of Just (Modal mt d) -> renderDialog d $ case mt of GoalModal -> drawModal s mt _ -> maybeScroll ModalViewport $ drawModal s mt @@ -633,7 +633,7 @@ drawModal s = \case RecipesModal -> availableListWidget (s ^. gameState) RecipeList CommandsModal -> commandsListWidget (s ^. gameState) MessagesModal -> availableListWidget (s ^. gameState) MessageList - StructuresModal -> SR.renderStructuresDisplay (s ^. gameState) (s ^. uiState . uiGameplay . uiStructure) + StructuresModal -> SR.renderStructuresDisplay (s ^. gameState) (s ^. uiState . uiGameplay . uiDialogs . uiStructure) ScenarioEndModal outcome -> padBottom (Pad 1) $ vBox $ @@ -650,7 +650,7 @@ drawModal s = \case DescriptionModal e -> descriptionWidget s e QuitModal -> padBottom (Pad 1) $ hCenter $ txt (quitMsg (s ^. uiState . uiMenu)) GoalModal -> - GR.renderGoalsDisplay (s ^. uiState . uiGameplay . uiGoal) $ + GR.renderGoalsDisplay (s ^. uiState . uiGameplay . uiDialogs . uiGoal) $ view (scenarioOperation . scenarioDescription) . fst <$> s ^. uiState . uiGameplay . scenarioRef KeepPlayingModal -> padLeftRight 1 $ @@ -1013,7 +1013,7 @@ drawKeyMenu s = creative = s ^. gameState . creativeMode showCreative = s ^. uiState . uiDebugOptions . Lens.contains ToggleCreative showEditor = s ^. uiState . uiDebugOptions . Lens.contains ToggleWorldEditor - goal = hasAnythingToShow $ s ^. uiState . uiGameplay . uiGoal . goalsContent + goal = hasAnythingToShow $ s ^. uiState . uiGameplay . uiDialogs . uiGoal . goalsContent showZero = s ^. uiState . uiGameplay . uiInventory . uiShowZero inventorySort = s ^. uiState . uiGameplay . uiInventory . uiInventorySort inventorySearch = s ^. uiState . uiGameplay . uiInventory . uiInventorySearch diff --git a/src/swarm-tui/Swarm/TUI/View/Objective.hs b/src/swarm-tui/Swarm/TUI/View/Objective.hs index a1a8efb6d..8d0224c9a 100644 --- a/src/swarm-tui/Swarm/TUI/View/Objective.hs +++ b/src/swarm-tui/Swarm/TUI/View/Objective.hs @@ -20,7 +20,7 @@ import Swarm.Game.Scenario.Objective import Swarm.Language.Syntax (Syntax) import Swarm.Language.Text.Markdown (Document) import Swarm.Language.Text.Markdown qualified as Markdown -import Swarm.TUI.Model.Goal +import Swarm.TUI.Model.Dialog.Goal import Swarm.TUI.Model.Name import Swarm.TUI.View.Attribute.Attr import Swarm.TUI.View.Util diff --git a/src/swarm-tui/Swarm/TUI/View/Popup.hs b/src/swarm-tui/Swarm/TUI/View/Popup.hs index 28cb197a8..96b30e62f 100644 --- a/src/swarm-tui/Swarm/TUI/View/Popup.hs +++ b/src/swarm-tui/Swarm/TUI/View/Popup.hs @@ -15,8 +15,8 @@ import Swarm.Game.Achievement.Definitions (title) import Swarm.Game.Achievement.Description (describe) import Swarm.Language.Syntax (constInfo, syntax) import Swarm.TUI.Model (AppState, Name, uiState) +import Swarm.TUI.Model.Dialog.Popup (Popup (..), currentPopup, popupFrames) import Swarm.TUI.Model.Event qualified as SE -import Swarm.TUI.Model.Popup (Popup (..), currentPopup, popupFrames) import Swarm.TUI.Model.UI (uiPopups) import Swarm.TUI.View.Attribute.Attr (notifAttr) import Swarm.TUI.View.Util (bindingText) diff --git a/src/swarm-tui/Swarm/TUI/View/Structure.hs b/src/swarm-tui/Swarm/TUI/View/Structure.hs index 24d458114..11a903ee3 100644 --- a/src/swarm-tui/Swarm/TUI/View/Structure.hs +++ b/src/swarm-tui/Swarm/TUI/View/Structure.hs @@ -32,8 +32,8 @@ import Swarm.Game.Scenario.Topography.Structure.Recognition.Type import Swarm.Game.State import Swarm.Game.State.Substate (structureRecognition) import Swarm.Language.Syntax.Direction (directionJsonModifier) +import Swarm.TUI.Model.Dialog.Structure import Swarm.TUI.Model.Name -import Swarm.TUI.Model.Structure import Swarm.TUI.View.Attribute.Attr import Swarm.TUI.View.CellDisplay import Swarm.TUI.View.Util diff --git a/src/swarm-web/Swarm/Web.hs b/src/swarm-web/Swarm/Web.hs index 4668876bf..9150939f5 100644 --- a/src/swarm-web/Swarm/Web.hs +++ b/src/swarm-web/Swarm/Web.hs @@ -78,7 +78,7 @@ import Swarm.Game.Step.Path.Type import Swarm.Language.Pipeline (processTermEither) import Swarm.Language.Pretty (prettyTextLine) import Swarm.TUI.Model hiding (SwarmKeyDispatchers (..)) -import Swarm.TUI.Model.Goal +import Swarm.TUI.Model.Dialog.Goal import Swarm.TUI.Model.Repl (REPLHistItem, replHistory, replSeq) import Swarm.TUI.Model.UI import Swarm.Util.RingBuffer @@ -200,7 +200,7 @@ goalsGraphHandler appStateRef = do uiGoalHandler :: IO AppState -> Handler GoalTracking uiGoalHandler appStateRef = do appState <- liftIO appStateRef - return $ appState ^. uiState . uiGameplay . uiGoal . goalsContent + return $ appState ^. uiState . uiGameplay . uiDialogs . uiGoal . goalsContent goalsHandler :: IO AppState -> Handler WinCondition goalsHandler appStateRef = do diff --git a/swarm.cabal b/swarm.cabal index ceccc5007..8e6eb1bda 100644 --- a/swarm.cabal +++ b/swarm.cabal @@ -1015,15 +1015,15 @@ library swarm-tui Swarm.TUI.Model Swarm.TUI.Model.Achievements Swarm.TUI.Model.DebugOption + Swarm.TUI.Model.Dialog.Goal + Swarm.TUI.Model.Dialog.Popup + Swarm.TUI.Model.Dialog.Structure Swarm.TUI.Model.Event - Swarm.TUI.Model.Goal Swarm.TUI.Model.KeyBindings Swarm.TUI.Model.Menu Swarm.TUI.Model.Name - Swarm.TUI.Model.Popup Swarm.TUI.Model.Repl Swarm.TUI.Model.StateUpdate - Swarm.TUI.Model.Structure Swarm.TUI.Model.UI Swarm.TUI.Model.WebCommand Swarm.TUI.Panel From f306950067f16484a10b52654850fc3e77934708 Mon Sep 17 00:00:00 2001 From: Karl Ostmo Date: Thu, 5 Sep 2024 15:06:47 -0700 Subject: [PATCH 2/3] move robot dialog rendering to new module --- src/swarm-tui/Swarm/TUI/View.hs | 146 +--------------------- src/swarm-tui/Swarm/TUI/View/Robot.hs | 167 ++++++++++++++++++++++++++ src/swarm-tui/Swarm/TUI/View/Util.hs | 9 ++ swarm.cabal | 1 + 4 files changed, 179 insertions(+), 144 deletions(-) create mode 100644 src/swarm-tui/Swarm/TUI/View/Robot.hs diff --git a/src/swarm-tui/Swarm/TUI/View.hs b/src/swarm-tui/Swarm/TUI/View.hs index 20f51a887..9d2215615 100644 --- a/src/swarm-tui/Swarm/TUI/View.hs +++ b/src/swarm-tui/Swarm/TUI/View.hs @@ -54,7 +54,6 @@ import Data.Bits (shiftL, shiftR, (.&.)) import Data.Foldable (toList) import Data.Foldable qualified as F import Data.Functor (($>)) -import Data.IntMap qualified as IM import Data.List (intersperse) import Data.List qualified as L import Data.List.Extra (enumerate) @@ -69,11 +68,8 @@ import Data.Set qualified as Set (toList) import Data.Text (Text) import Data.Text qualified as T import Data.Time (NominalDiffTime, defaultTimeLocale, formatTime) -import Linear import Network.Wai.Handler.Warp (Port) -import Numeric (showFFloat) import Swarm.Constant -import Swarm.Game.CESK (CESK (..)) import Swarm.Game.Device (commandCost, commandsForDeviceCaps, enabledCommands, getMap, ingredients) import Swarm.Game.Display import Swarm.Game.Entity as E @@ -82,7 +78,6 @@ import Swarm.Game.Land import Swarm.Game.Location import Swarm.Game.Recipe import Swarm.Game.Robot -import Swarm.Game.Robot.Activity import Swarm.Game.Robot.Concrete import Swarm.Game.Scenario ( scenarioAuthor, @@ -114,7 +109,7 @@ import Swarm.Game.State.Landscape import Swarm.Game.State.Robot import Swarm.Game.State.Runtime import Swarm.Game.State.Substate -import Swarm.Game.Tick (TickNumber (..), addTicks) +import Swarm.Game.Tick (TickNumber (..)) import Swarm.Game.Universe import Swarm.Game.World.Coords import Swarm.Game.World.Gen (Seed) @@ -146,12 +141,10 @@ import Swarm.TUI.View.CellDisplay import Swarm.TUI.View.Logo import Swarm.TUI.View.Objective qualified as GR import Swarm.TUI.View.Popup +import Swarm.TUI.View.Robot import Swarm.TUI.View.Structure qualified as SR import Swarm.TUI.View.Util as VU import Swarm.Util -import Swarm.Util.UnitInterval -import Swarm.Util.WindowedCounter qualified as WC -import System.Clock (TimeSpec (..)) import Text.Printf import Text.Wrap import Witch (into) @@ -507,14 +500,6 @@ drawGameUI s = ) ] -renderCoordsString :: Cosmic Location -> String -renderCoordsString (Cosmic sw coords) = - unwords $ VU.locationToString coords : suffix - where - suffix = case sw of - DefaultRootSubworld -> [] - SubworldName swName -> ["in", T.unpack swName] - drawWorldCursorInfo :: WorldOverdraw -> GameState -> Cosmic Coords -> Widget Name drawWorldCursorInfo worldEditor g cCoords = case getStatic g coords of @@ -660,133 +645,6 @@ drawModal s = \case TerrainPaletteModal -> EV.drawTerrainSelector s EntityPaletteModal -> EV.drawEntityPaintSelector s --- | Render the percentage of ticks that this robot was active. --- This indicator can take some time to "warm up" and stabilize --- due to the sliding window. --- --- == Use of previous tick --- The 'Swarm.Game.Step.gameTick' function runs all robots, then increments the current tick. --- So at the time we are rendering a frame, the current tick will always be --- strictly greater than any ticks stored in the 'WC.WindowedCounter' for any robot; --- hence 'WC.getOccupancy' will never be @1@ if we use the current tick directly as --- obtained from the 'ticks' function. --- So we "rewind" it to the previous tick for the purpose of this display. -renderDutyCycle :: GameState -> Robot -> Widget Name -renderDutyCycle gs robot = - withAttr dutyCycleAttr . str . flip (showFFloat (Just 1)) "%" $ dutyCyclePercentage - where - curTicks = gs ^. temporal . ticks - window = robot ^. activityCounts . activityWindow - - -- Rewind to previous tick - latestRobotTick = addTicks (-1) curTicks - dutyCycleRatio = WC.getOccupancy latestRobotTick window - - dutyCycleAttr = safeIndex dutyCycleRatio meterAttributeNames - - dutyCyclePercentage :: Double - dutyCyclePercentage = 100 * getValue dutyCycleRatio - -robotsListWidget :: AppState -> Widget Name -robotsListWidget s = hCenter table - where - table = - BT.renderTable - . BT.columnBorders False - . BT.setDefaultColAlignment BT.AlignCenter - -- Inventory count is right aligned - . BT.alignRight 4 - . BT.table - $ map (padLeftRight 1) <$> (headers : robotsTable) - headings = - [ "Name" - , "Age" - , "Pos" - , "Items" - , "Status" - , "Actns" - , "Cmds" - , "Cycles" - , "Activity" - , "Log" - ] - headers = withAttr robotAttr . txt <$> applyWhen debugRID ("ID" :) headings - robotsTable = 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 (s ^. gameState) 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 _ = s ^. uiState . uiGameplay . uiTiming . 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 - (s ^. uiState . uiGameplay) - 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 = s ^. uiState . uiDebugOptions . Lens.contains ListRobotIDs - debugAllRobots = s ^. uiState . uiDebugOptions . Lens.contains ListAllRobots - g = s ^. gameState - helpWidget :: Seed -> Maybe Port -> KeyEventHandlingState -> Widget Name helpWidget theSeed mport keyState = padLeftRight 2 . vBox $ padTop (Pad 1) <$> [info, helpKeys, tips] diff --git a/src/swarm-tui/Swarm/TUI/View/Robot.hs b/src/swarm-tui/Swarm/TUI/View/Robot.hs new file mode 100644 index 000000000..93ff2415b --- /dev/null +++ b/src/swarm-tui/Swarm/TUI/View/Robot.hs @@ -0,0 +1,167 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE NoGeneralizedNewtypeDeriving #-} + +-- | +-- SPDX-License-Identifier: BSD-3-Clause +-- +-- A UI-centric model for presentation of Robot details. +module Swarm.TUI.View.Robot where + +import Brick hiding (Direction, Location) +import Brick.Widgets.Center (hCenter) +import Brick.Widgets.Table qualified as BT +import Control.Lens as Lens hiding (Const, from) +import Data.IntMap qualified as IM +import Data.Map qualified as M +import Data.Maybe (fromMaybe) +import Linear +import Numeric (showFFloat) +import Swarm.Game.CESK (CESK (..)) +import Swarm.Game.Entity as E +import Swarm.Game.Location +import Swarm.Game.Robot +import Swarm.Game.Robot.Activity +import Swarm.Game.Robot.Concrete +import Swarm.Game.State +import Swarm.Game.State.Robot +import Swarm.Game.State.Substate +import Swarm.Game.Tick (addTicks) +import Swarm.Game.Universe +import Swarm.Game.World.Coords +import Swarm.TUI.Model +import Swarm.TUI.Model.DebugOption (DebugOption (..)) +import Swarm.TUI.Model.UI +import Swarm.TUI.View.Attribute.Attr +import Swarm.TUI.View.CellDisplay +import Swarm.TUI.View.Util as VU +import Swarm.Util +import Swarm.Util.UnitInterval +import Swarm.Util.WindowedCounter qualified as WC +import System.Clock (TimeSpec (..)) + +-- | Render the percentage of ticks that this robot was active. +-- This indicator can take some time to "warm up" and stabilize +-- due to the sliding window. +-- +-- == Use of previous tick +-- The 'Swarm.Game.Step.gameTick' function runs all robots, then increments the current tick. +-- So at the time we are rendering a frame, the current tick will always be +-- strictly greater than any ticks stored in the 'WC.WindowedCounter' for any robot; +-- hence 'WC.getOccupancy' will never be @1@ if we use the current tick directly as +-- obtained from the 'ticks' function. +-- So we "rewind" it to the previous tick for the purpose of this display. +renderDutyCycle :: GameState -> Robot -> Widget Name +renderDutyCycle gs robot = + withAttr dutyCycleAttr . str . flip (showFFloat (Just 1)) "%" $ dutyCyclePercentage + where + curTicks = gs ^. temporal . ticks + window = robot ^. activityCounts . activityWindow + + -- Rewind to previous tick + latestRobotTick = addTicks (-1) curTicks + dutyCycleRatio = WC.getOccupancy latestRobotTick window + + dutyCycleAttr = safeIndex dutyCycleRatio meterAttributeNames + + dutyCyclePercentage :: Double + dutyCyclePercentage = 100 * getValue dutyCycleRatio + +robotsListWidget :: AppState -> Widget Name +robotsListWidget s = hCenter table + where + table = + BT.renderTable + . BT.columnBorders False + . BT.setDefaultColAlignment BT.AlignCenter + -- Inventory count is right aligned + . BT.alignRight 4 + . BT.table + $ map (padLeftRight 1) <$> (headers : robotsTable) + headings = + [ "Name" + , "Age" + , "Pos" + , "Items" + , "Status" + , "Actns" + , "Cmds" + , "Cycles" + , "Activity" + , "Log" + ] + headers = withAttr robotAttr . txt <$> applyWhen debugRID ("ID" :) headings + robotsTable = 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 (s ^. gameState) 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 _ = s ^. uiState . uiGameplay . uiTiming . 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 + (s ^. uiState . uiGameplay) + 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 = s ^. uiState . uiDebugOptions . Lens.contains ListRobotIDs + debugAllRobots = s ^. uiState . uiDebugOptions . Lens.contains ListAllRobots + g = s ^. gameState diff --git a/src/swarm-tui/Swarm/TUI/View/Util.hs b/src/swarm-tui/Swarm/TUI/View/Util.hs index 69f0b2869..63c3fe39e 100644 --- a/src/swarm-tui/Swarm/TUI/View/Util.hs +++ b/src/swarm-tui/Swarm/TUI/View/Util.hs @@ -25,6 +25,7 @@ import Swarm.Game.State import Swarm.Game.State.Landscape import Swarm.Game.State.Substate import Swarm.Game.Terrain +import Swarm.Game.Universe import Swarm.Language.Pretty (prettyTextLine) import Swarm.Language.Syntax (Syntax) import Swarm.Language.Text.Markdown qualified as Markdown @@ -255,3 +256,11 @@ bindingText s e = maybe "" ppBindingShort b Binding V.KLeft m | null m -> "←" Binding V.KRight m | null m -> "→" bi -> ppBinding bi + +renderCoordsString :: Cosmic Location -> String +renderCoordsString (Cosmic sw coords) = + unwords $ locationToString coords : suffix + where + suffix = case sw of + DefaultRootSubworld -> [] + SubworldName swName -> ["in", T.unpack swName] diff --git a/swarm.cabal b/swarm.cabal index 8e6eb1bda..f8ab89dad 100644 --- a/swarm.cabal +++ b/swarm.cabal @@ -1036,6 +1036,7 @@ library swarm-tui Swarm.TUI.View.Logo Swarm.TUI.View.Objective Swarm.TUI.View.Popup + Swarm.TUI.View.Robot Swarm.TUI.View.Structure Swarm.TUI.View.Util From ad020197f7fbd8a93fa7b39313bb5ff9360faf44 Mon Sep 17 00:00:00 2001 From: Karl Ostmo Date: Fri, 6 Sep 2024 22:39:30 -0700 Subject: [PATCH 3/3] module for re-exports --- src/swarm-tui/Swarm/TUI/Controller.hs | 4 +--- src/swarm-tui/Swarm/TUI/Model/Dialog.hs | 9 +++++++++ src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs | 3 +-- src/swarm-tui/Swarm/TUI/Model/UI.hs | 4 +--- swarm.cabal | 1 + 5 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 src/swarm-tui/Swarm/TUI/Model/Dialog.hs diff --git a/src/swarm-tui/Swarm/TUI/Controller.hs b/src/swarm-tui/Swarm/TUI/Controller.hs index 8dce913f3..4410422c8 100644 --- a/src/swarm-tui/Swarm/TUI/Controller.hs +++ b/src/swarm-tui/Swarm/TUI/Controller.hs @@ -96,9 +96,7 @@ import Swarm.TUI.Launch.Model import Swarm.TUI.Launch.Prep (prepareLaunchDialog) import Swarm.TUI.List import Swarm.TUI.Model -import Swarm.TUI.Model.Dialog.Goal -import Swarm.TUI.Model.Dialog.Popup (progressPopups) -import Swarm.TUI.Model.Dialog.Structure +import Swarm.TUI.Model.Dialog import Swarm.TUI.Model.Name import Swarm.TUI.Model.Repl import Swarm.TUI.Model.StateUpdate diff --git a/src/swarm-tui/Swarm/TUI/Model/Dialog.hs b/src/swarm-tui/Swarm/TUI/Model/Dialog.hs new file mode 100644 index 000000000..95baff1f9 --- /dev/null +++ b/src/swarm-tui/Swarm/TUI/Model/Dialog.hs @@ -0,0 +1,9 @@ +module Swarm.TUI.Model.Dialog ( + module Swarm.TUI.Model.Dialog.Goal, + module Swarm.TUI.Model.Dialog.Popup, + module Swarm.TUI.Model.Dialog.Structure, +) where + +import Swarm.TUI.Model.Dialog.Goal +import Swarm.TUI.Model.Dialog.Popup +import Swarm.TUI.Model.Dialog.Structure diff --git a/src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs b/src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs index ca088b1ea..f519e411d 100644 --- a/src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs +++ b/src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs @@ -82,8 +82,7 @@ import Swarm.TUI.Launch.Model (toSerializableParams) import Swarm.TUI.Model import Swarm.TUI.Model.Achievements import Swarm.TUI.Model.DebugOption (DebugOption (LoadTestingScenarios)) -import Swarm.TUI.Model.Dialog.Goal (emptyGoalDisplay) -import Swarm.TUI.Model.Dialog.Structure +import Swarm.TUI.Model.Dialog import Swarm.TUI.Model.KeyBindings import Swarm.TUI.Model.Name import Swarm.TUI.Model.Repl diff --git a/src/swarm-tui/Swarm/TUI/Model/UI.hs b/src/swarm-tui/Swarm/TUI/Model/UI.hs index e0a07f58e..4fcddcc8b 100644 --- a/src/swarm-tui/Swarm/TUI/Model/UI.hs +++ b/src/swarm-tui/Swarm/TUI/Model/UI.hs @@ -89,9 +89,7 @@ import Swarm.TUI.Inventory.Sorting import Swarm.TUI.Launch.Model import Swarm.TUI.Launch.Prep import Swarm.TUI.Model.DebugOption (DebugOption) -import Swarm.TUI.Model.Dialog.Goal -import Swarm.TUI.Model.Dialog.Popup -import Swarm.TUI.Model.Dialog.Structure +import Swarm.TUI.Model.Dialog import Swarm.TUI.Model.Menu import Swarm.TUI.Model.Name import Swarm.TUI.Model.Repl diff --git a/swarm.cabal b/swarm.cabal index f8ab89dad..08967a931 100644 --- a/swarm.cabal +++ b/swarm.cabal @@ -1015,6 +1015,7 @@ library swarm-tui Swarm.TUI.Model Swarm.TUI.Model.Achievements Swarm.TUI.Model.DebugOption + Swarm.TUI.Model.Dialog Swarm.TUI.Model.Dialog.Goal Swarm.TUI.Model.Dialog.Popup Swarm.TUI.Model.Dialog.Structure