swarm-0.7.0.0: src/swarm-tui/Swarm/TUI/Model/Event.hs
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE OverloadedStrings #-}
-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Sum types representing the Swarm events
-- abstracted away from keybindings.
module Swarm.TUI.Model.Event (
SwarmEvent (..),
MainEvent (..),
REPLEvent (..),
WorldEvent (..),
RobotEvent (..),
swarmEvents,
defaultSwarmBindings,
) where
import Brick.Keybindings
import Control.Arrow ((&&&))
import Data.Bifunctor (first)
import Data.List.Extra (enumerate)
import Data.Text (Text)
import GHC.Generics (Generic)
import Generic.Data (FiniteEnumeration (..))
import Graphics.Vty qualified as V
import Swarm.Language.Syntax.Direction (AbsoluteDir (..), Direction (..), directionSyntax)
-- | Swarm named TUI event type.
--
-- See Note [how Swarm event handlers work]
data SwarmEvent
= Main MainEvent
| REPL REPLEvent
| World WorldEvent
| Robot RobotEvent
deriving (Eq, Ord, Show, Generic)
deriving (Enum, Bounded) via (FiniteEnumeration SwarmEvent)
swarmEvents :: KeyEvents SwarmEvent
swarmEvents =
keyEvents $
concat
[ embed Main mainEvents
, embed REPL replEvents
, embed World worldPanelEvents
, embed Robot robotPanelEvents
]
where
embed f = map (fmap f) . keyEventsList
defaultSwarmBindings :: [(SwarmEvent, [Binding])]
defaultSwarmBindings =
concat
[ embed Main defaultMainBindings
, embed REPL defaultReplBindings
, embed World defaultWorldPanelBindings
, embed Robot defaultRobotPanelBindings
]
where
embed = map . first
-- ----------------------------------------------
-- MAIN EVENTS
-- ----------------------------------------------
-- | Main abstract keybinding events while running the game itself.
--
-- See 'Swarm.TUI.Controller.MainEventHandler.'.
data MainEvent
= QuitEvent
| ViewHelpEvent
| ViewRobotsEvent
| ViewRecipesEvent
| ViewCommandsEvent
| ViewMessagesEvent
| ViewStructuresEvent
| ViewGoalEvent
| HideRobotsEvent
| ShowCESKDebugEvent
| PauseEvent
| RunSingleTickEvent
| IncreaseTpsEvent
| DecreaseTpsEvent
| FocusWorldEvent
| FocusRobotEvent
| FocusREPLEvent
| FocusInfoEvent
| ToggleCreativeModeEvent
| ToggleWorldEditorEvent
| ToggleREPLVisibilityEvent
| ViewBaseEvent
| ToggleFPSEvent
deriving (Eq, Ord, Show, Enum, Bounded)
mainEvents :: KeyEvents MainEvent
mainEvents = allKeyEvents $ \case
QuitEvent -> "quit"
ViewHelpEvent -> "view help"
ViewRobotsEvent -> "view robots"
ViewRecipesEvent -> "view recipes"
ViewCommandsEvent -> "view commands"
ViewMessagesEvent -> "view messages"
ViewStructuresEvent -> "view structures"
ViewGoalEvent -> "view goal"
HideRobotsEvent -> "hide robots"
ShowCESKDebugEvent -> "debug CESK"
PauseEvent -> "pause"
RunSingleTickEvent -> "run single tick"
IncreaseTpsEvent -> "increse TPS"
DecreaseTpsEvent -> "decrease TPS"
FocusWorldEvent -> "focus World"
FocusRobotEvent -> "focus Robot"
FocusREPLEvent -> "focus REPL"
FocusInfoEvent -> "focus Info"
ToggleCreativeModeEvent -> "creative mode"
ToggleWorldEditorEvent -> "world editor"
ToggleREPLVisibilityEvent -> "toggle REPL"
ViewBaseEvent -> "view base robot"
ToggleFPSEvent -> "toggle FPS"
defaultMainBindings :: [(MainEvent, [Binding])]
defaultMainBindings = allBindings $ \case
QuitEvent -> [ctrl 'q']
ViewHelpEvent -> [fn 1]
ViewRobotsEvent -> [fn 2]
ViewRecipesEvent -> [fn 3]
ViewCommandsEvent -> [fn 4]
ViewMessagesEvent -> [fn 5]
ViewStructuresEvent -> [fn 6]
ViewGoalEvent -> [ctrl 'g']
HideRobotsEvent -> [meta 'h']
ShowCESKDebugEvent -> [meta 'd']
PauseEvent -> [ctrl 'p']
RunSingleTickEvent -> [ctrl 'o']
IncreaseTpsEvent -> [ctrl 'x']
DecreaseTpsEvent -> [ctrl 'z']
FocusWorldEvent -> [meta 'w']
FocusRobotEvent -> [meta 'e']
FocusREPLEvent -> [meta 'r']
FocusInfoEvent -> [meta 't']
ToggleCreativeModeEvent -> [ctrl 'v']
ToggleWorldEditorEvent -> []
ToggleREPLVisibilityEvent -> [meta ',']
ViewBaseEvent -> [meta 'c']
ToggleFPSEvent -> [meta 'f']
-- ----------------------------------------------
-- REPL EVENTS
-- ----------------------------------------------
-- | REPL abstract keybinding events.
--
-- See 'Swarm.TUI.Controller.REPLEventHandler'.
data REPLEvent
= CancelRunningProgramEvent
| TogglePilotingModeEvent
| ToggleCustomKeyHandlingEvent
deriving (Eq, Ord, Show, Enum, Bounded)
replEvents :: KeyEvents REPLEvent
replEvents = allKeyEvents $ \case
CancelRunningProgramEvent -> "cancel running program"
ToggleCustomKeyHandlingEvent -> "toggle custom key handling"
TogglePilotingModeEvent -> "toggle piloting mode"
defaultReplBindings :: [(REPLEvent, [Binding])]
defaultReplBindings = allBindings $ \case
CancelRunningProgramEvent -> [ctrl 'c', bind V.KEsc]
TogglePilotingModeEvent -> [meta 'p']
ToggleCustomKeyHandlingEvent -> [meta 'k']
-- ----------------------------------------------
-- REPL EVENTS
-- ----------------------------------------------
newtype WorldEvent
= MoveViewEvent AbsoluteDir
deriving (Eq, Ord, Show, Generic)
deriving (Enum, Bounded) via (FiniteEnumeration WorldEvent)
worldPanelEvents :: KeyEvents WorldEvent
worldPanelEvents = allKeyEvents $ \case
MoveViewEvent d -> "move view " <> directionSyntax (DAbsolute d)
defaultWorldPanelBindings :: [(WorldEvent, [Binding])]
defaultWorldPanelBindings = allBindings $ \case
MoveViewEvent DWest -> [bind V.KLeft, bind 'h']
MoveViewEvent DSouth -> [bind V.KDown, bind 'j']
MoveViewEvent DNorth -> [bind V.KUp, bind 'k']
MoveViewEvent DEast -> [bind V.KRight, bind 'l']
-- ----------------------------------------------
-- ROBOT EVENTS
-- ----------------------------------------------
data RobotEvent
= MakeEntityEvent
| ShowZeroInventoryEntitiesEvent
| CycleInventorySortEvent
| SwitchInventorySortDirection
| SearchInventoryEvent
deriving (Eq, Ord, Show, Enum, Bounded)
robotPanelEvents :: KeyEvents RobotEvent
robotPanelEvents = allKeyEvents $ \case
MakeEntityEvent -> "make entity"
ShowZeroInventoryEntitiesEvent -> "show zero inventory entities"
CycleInventorySortEvent -> "cycle inventory sort"
SwitchInventorySortDirection -> "switch inventory direction"
SearchInventoryEvent -> "search inventory"
defaultRobotPanelBindings :: [(RobotEvent, [Binding])]
defaultRobotPanelBindings = allBindings $ \case
MakeEntityEvent -> [bind 'm']
ShowZeroInventoryEntitiesEvent -> [bind '0']
CycleInventorySortEvent -> [bind ';']
SwitchInventorySortDirection -> [bind ':']
SearchInventoryEvent -> [bind '/']
-- ----------------
-- Helper methods
allKeyEvents :: (Ord e, Bounded e, Enum e) => (e -> Text) -> KeyEvents e
allKeyEvents f = keyEvents $ map (f &&& id) enumerate
allBindings :: (Bounded e, Enum e) => (e -> [Binding]) -> [(e, [Binding])]
allBindings f = map (\e -> (e, f e)) enumerate