swarm-0.7.0.0: src/swarm-tui/Swarm/TUI/Model/UI.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ViewPatterns #-}
-- |
-- SPDX-License-Identifier: BSD-3-Clause
module Swarm.TUI.Model.UI (
UIState (..),
uiMenu,
uiPlaying,
uiDebugOptions,
uiLaunchConfig,
uiAttrMap,
-- ** Initialization
initFocusRing,
defaultInitLgTicksPerSecond,
initUIState,
UIInitOptions (..),
) where
import Brick (AttrMap)
import Brick.Focus
import Control.Effect.Accum
import Control.Effect.Lift
import Control.Lens hiding (from, (<.>))
import Data.List.Extra (enumerate)
import Data.Sequence (Seq)
import Data.Set (Set)
import Swarm.Failure (SystemFailure)
import Swarm.TUI.Launch.Model
import Swarm.TUI.Launch.Prep
import Swarm.TUI.Model.DebugOption (DebugOption)
import Swarm.TUI.Model.Menu
import Swarm.TUI.Model.Name
import Swarm.TUI.View.Attribute.Attr (swarmAttrMap)
import Swarm.Util.Lens (makeLensesNoSigs)
-- * Toplevel UIState definition
-- | UI state independent of an actively-playing scenario.
-- Compare to 'UIGameplay', which contains UI state for an
-- active scenario.
data UIState = UIState
{ _uiMenu :: Menu
, _uiPlaying :: Bool
, _uiDebugOptions :: Set DebugOption
, _uiLaunchConfig :: LaunchOptions
, _uiAttrMap :: AttrMap
}
-- * Lenses for UIState
makeLensesNoSigs ''UIState
-- | The current menu state.
uiMenu :: Lens' UIState Menu
-- | Are we currently playing the game?
--
-- * 'True' = we are playing, and
-- should thus display a world, REPL, etc.
-- * False = we should
-- display the current menu.
uiPlaying :: Lens' UIState Bool
-- | Debugging features, for example are we allowed to turn creative mode on and off?
uiDebugOptions :: Lens' UIState (Set DebugOption)
-- | Configuration modal when launching a scenario
uiLaunchConfig :: Lens' UIState LaunchOptions
-- | Attribute map
uiAttrMap :: Lens' UIState AttrMap
-- * UIState initialization
-- | The initial state of the focus ring.
-- NOTE: Normally, the Tab key might cycle through the members of the
-- focus ring. However, the REPL already uses Tab. So, to is not used
-- at all right now for navigating the toplevel focus ring.
initFocusRing :: FocusRing Name
initFocusRing = focusRing $ map FocusablePanel enumerate
-- | The initial tick speed.
defaultInitLgTicksPerSecond :: Int
defaultInitLgTicksPerSecond = 4 -- 2^4 = 16 ticks / second
data UIInitOptions = UIInitOptions
{ speed :: Int
, showMainMenu :: Bool
, autoShowObjectives :: Bool
, debugOptions :: Set DebugOption
}
deriving (Eq, Show)
-- | Initialize the UI state. This needs to be in the IO monad since
-- it involves reading a REPL history file, getting the current
-- time, and loading text files from the data directory.
initUIState ::
( Has (Accum (Seq SystemFailure)) sig m
, Has (Lift IO) sig m
) =>
UIInitOptions ->
m UIState
initUIState UIInitOptions {..} = do
launchConfigPanel <- sendIO initConfigPanel
return
UIState
{ _uiMenu = if showMainMenu then MainMenu (mainMenu NewGame) else NoMenu
, _uiPlaying = not showMainMenu
, _uiDebugOptions = debugOptions
, _uiLaunchConfig = launchConfigPanel
, _uiAttrMap = swarmAttrMap
}