-- |
-- SPDX-License-Identifier: BSD-3-Clause
module Swarm.TUI.Editor.View where

import Brick hiding (Direction)
import Brick.Focus
import Brick.Widgets.Center (hCenter)
import Brick.Widgets.List qualified as BL
import Control.Lens hiding (Const, from)
import Data.List qualified as L
import Swarm.Game.Scenario.Topography.Area qualified as EA
import Swarm.Game.Scenario.Topography.EntityFacade
import Swarm.Game.Terrain (TerrainType)
import Swarm.Game.Universe
import Swarm.Game.World qualified as W
import Swarm.TUI.Border
import Swarm.TUI.Editor.Model
import Swarm.TUI.Model
import Swarm.TUI.Model.Name
import Swarm.TUI.Model.UI
import Swarm.TUI.Panel
import Swarm.TUI.View.Attribute.Attr
import Swarm.TUI.View.CellDisplay (renderDisplay)
import Swarm.TUI.View.Util qualified as VU
import Swarm.Util (listEnums)

drawWorldEditor :: FocusRing Name -> UIState -> Widget Name
drawWorldEditor :: FocusRing Name -> UIState -> Widget Name
drawWorldEditor FocusRing Name
toplevelFocusRing UIState
uis =
  if WorldEditor Name
worldEditor forall s a. s -> Getting a s a -> a
^. forall n. Lens' (WorldEditor n) WorldOverdraw
worldOverdraw forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens' WorldOverdraw Bool
isWorldEditorEnabled
    then
      forall n.
Eq n =>
AttrName
-> FocusRing n -> n -> BorderLabels n -> Widget n -> Widget n
panel
        AttrName
highlightAttr
        FocusRing Name
toplevelFocusRing
        (FocusablePanel -> Name
FocusablePanel FocusablePanel
WorldEditorPanel)
        forall n. BorderLabels n
plainBorder
        Widget Name
innerWidget
    else forall n. Widget n
emptyWidget
 where
  privateFocusRing :: FocusRing Name
privateFocusRing = WorldEditor Name
worldEditor forall s a. s -> Getting a s a -> a
^. forall n. Lens' (WorldEditor n) (FocusRing n)
editorFocusRing
  maybeCurrentFocus :: Maybe Name
maybeCurrentFocus = forall n. FocusRing n -> Maybe n
focusGetCurrent FocusRing Name
privateFocusRing

  controlsBox :: Widget Name
controlsBox =
    forall n. Padding -> Widget n -> Widget n
padBottom Padding
Max forall a b. (a -> b) -> a -> b
$
      forall n. [Widget n] -> Widget n
vBox
        [ Widget Name
brushWidget
        , Widget Name
entityWidget
        , Widget Name
clearEntityButtonWidget
        , Widget Name
areaWidget
        , Widget Name
outputWidget
        , forall n. String -> Widget n
str String
" "
        , Widget Name
saveButtonWidget
        ]

  innerWidget :: Widget Name
innerWidget =
    forall n. Int -> Widget n -> Widget n
padLeftRight Int
1 forall a b. (a -> b) -> a -> b
$
      forall n. Int -> Widget n -> Widget n
hLimit Int
30 forall a b. (a -> b) -> a -> b
$
        Widget Name
controlsBox forall n. Widget n -> Widget n -> Widget n
<=> forall n. Widget n
statusBox

  worldEditor :: WorldEditor Name
worldEditor = UIState
uis forall s a. s -> Getting a s a -> a
^. Lens' UIState (WorldEditor Name)
uiWorldEditor
  maybeAreaBounds :: Maybe (Cosmic BoundsRectangle)
maybeAreaBounds = WorldEditor Name
worldEditor forall s a. s -> Getting a s a -> a
^. forall n. Lens' (WorldEditor n) MapEditingBounds
editingBounds forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens' MapEditingBounds (Maybe (Cosmic BoundsRectangle))
boundsRect

  -- TODO (#1150): Use withFocusRing?
  mkFormControl :: Name -> Widget Name -> Widget Name
mkFormControl Name
n Widget Name
w =
    forall n. Ord n => n -> Widget n -> Widget n
clickable Name
n forall a b. (a -> b) -> a -> b
$ forall {n}. Widget n -> Widget n
transformation Widget Name
w
   where
    transformation :: Widget n -> Widget n
transformation =
      if forall a. a -> Maybe a
Just Name
n forall a. Eq a => a -> a -> Bool
== Maybe Name
maybeCurrentFocus
        then forall n. AttrName -> Widget n -> Widget n
withAttr AttrName
BL.listSelectedFocusedAttr
        else forall a. a -> a
id

  swatchContent :: GenericList n t a -> (a -> Widget n) -> Widget n
swatchContent GenericList n t a
list a -> Widget n
drawFunc =
    forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall n. Widget n
emptyWidget a -> Widget n
drawFunc Maybe a
selectedThing
   where
    selectedThing :: Maybe a
selectedThing = forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) e n.
(Splittable t, Traversable t, Semigroup (t e)) =>
GenericList n t e -> Maybe (Int, e)
BL.listSelectedElement GenericList n t a
list

  brushWidget :: Widget Name
brushWidget =
    Name -> Widget Name -> Widget Name
mkFormControl (WorldEditorFocusable -> Name
WorldEditorPanelControl WorldEditorFocusable
BrushSelector) forall a b. (a -> b) -> a -> b
$
      forall n. Padding -> Widget n -> Widget n
padRight (Int -> Padding
Pad Int
1) (forall n. String -> Widget n
str String
"Brush:")
        forall n. Widget n -> Widget n -> Widget n
<+> forall {t :: * -> *} {a} {n} {n}.
(Splittable t, Traversable t, Semigroup (t a)) =>
GenericList n t a -> (a -> Widget n) -> Widget n
swatchContent (WorldEditor Name
worldEditor forall s a. s -> Getting a s a -> a
^. forall n. Lens' (WorldEditor n) (List n TerrainType)
terrainList) TerrainType -> Widget Name
VU.drawLabeledTerrainSwatch

  entityWidget :: Widget Name
entityWidget =
    Name -> Widget Name -> Widget Name
mkFormControl (WorldEditorFocusable -> Name
WorldEditorPanelControl WorldEditorFocusable
EntitySelector) forall a b. (a -> b) -> a -> b
$
      forall n. Padding -> Widget n -> Widget n
padRight (Int -> Padding
Pad Int
1) (forall n. String -> Widget n
str String
"Entity:")
        forall n. Widget n -> Widget n -> Widget n
<+> forall {t :: * -> *} {a} {n} {n}.
(Splittable t, Traversable t, Semigroup (t a)) =>
GenericList n t a -> (a -> Widget n) -> Widget n
swatchContent (WorldEditor Name
worldEditor forall s a. s -> Getting a s a -> a
^. forall n. Lens' (WorldEditor n) (List n EntityFacade)
entityPaintList) EntityFacade -> Widget Name
drawLabeledEntitySwatch

  clearEntityButtonWidget :: Widget Name
clearEntityButtonWidget =
    if forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall a b. (a -> b) -> a -> b
$ WorldEditor Name
worldEditor forall s a. s -> Getting a s a -> a
^. forall n. Lens' (WorldEditor n) (List n EntityFacade)
entityPaintList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n (t :: * -> *) e. Lens' (GenericList n t e) (Maybe Int)
BL.listSelectedL
      then forall n. Widget n
emptyWidget
      else
        Name -> Widget Name -> Widget Name
mkFormControl (WorldEditorFocusable -> Name
WorldEditorPanelControl WorldEditorFocusable
ClearEntityButton)
          forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. Int -> Widget n -> Widget n
hLimit Int
20
          forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {n}. Widget n -> Widget n
hCenter
          forall a b. (a -> b) -> a -> b
$ forall n. String -> Widget n
str String
"None"

  areaContent :: Widget n
areaContent = case WorldEditor Name
worldEditor forall s a. s -> Getting a s a -> a
^. forall n. Lens' (WorldEditor n) MapEditingBounds
editingBounds forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens' MapEditingBounds BoundsSelectionStep
boundsSelectionStep of
    BoundsSelectionStep
UpperLeftPending -> forall n. String -> Widget n
str String
"Click top-left"
    LowerRightPending Cosmic Coords
_wcoords -> forall n. String -> Widget n
str String
"Click bottom-right"
    BoundsSelectionStep
SelectionComplete -> forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall n. Widget n
emptyWidget (forall {n}. BoundsRectangle -> Widget n
renderBounds forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view forall a1 a2. Lens (Cosmic a1) (Cosmic a2) a1 a2
planar) Maybe (Cosmic BoundsRectangle)
maybeAreaBounds

  areaWidget :: Widget Name
areaWidget =
    Name -> Widget Name -> Widget Name
mkFormControl (WorldEditorFocusable -> Name
WorldEditorPanelControl WorldEditorFocusable
AreaSelector) forall a b. (a -> b) -> a -> b
$
      forall n. [Widget n] -> Widget n
vBox
        [ forall n. String -> Widget n
str String
"Area:"
        , forall n. Widget n
areaContent
        ]

  renderBounds :: BoundsRectangle -> Widget n
renderBounds (Coords
upperLeftCoord, Coords
lowerRightCoord) =
    forall n. String -> Widget n
str forall a b. (a -> b) -> a -> b
$
      [String] -> String
unwords forall a b. (a -> b) -> a -> b
$
        forall a. a -> [a] -> [a]
L.intersperse
          String
"@"
          [ AreaDimensions -> String
EA.renderRectDimensions AreaDimensions
rectArea
          , Location -> String
VU.locationToString Location
upperLeftLoc
          ]
   where
    upperLeftLoc :: Location
upperLeftLoc = Coords -> Location
W.coordsToLoc Coords
upperLeftCoord
    lowerRightLoc :: Location
lowerRightLoc = Coords -> Location
W.coordsToLoc Coords
lowerRightCoord
    rectArea :: AreaDimensions
rectArea = Location -> Location -> AreaDimensions
EA.cornersToArea Location
upperLeftLoc Location
lowerRightLoc

  outputWidget :: Widget Name
outputWidget =
    Name -> Widget Name -> Widget Name
mkFormControl (WorldEditorFocusable -> Name
WorldEditorPanelControl WorldEditorFocusable
OutputPathSelector) forall a b. (a -> b) -> a -> b
$
      forall n. Padding -> Widget n -> Widget n
padRight (Int -> Padding
Pad Int
1) (forall n. String -> Widget n
str String
"Output:") forall n. Widget n -> Widget n -> Widget n
<+> forall n. Widget n
outputWidgetContent

  outputWidgetContent :: Widget n
outputWidgetContent = forall n. String -> Widget n
str forall a b. (a -> b) -> a -> b
$ WorldEditor Name
worldEditor forall s a. s -> Getting a s a -> a
^. forall n. Lens' (WorldEditor n) String
outputFilePath

  saveButtonWidget :: Widget Name
saveButtonWidget =
    Name -> Widget Name -> Widget Name
mkFormControl (WorldEditorFocusable -> Name
WorldEditorPanelControl WorldEditorFocusable
MapSaveButton)
      forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. Int -> Widget n -> Widget n
hLimit Int
20
      forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {n}. Widget n -> Widget n
hCenter
      forall a b. (a -> b) -> a -> b
$ forall n. String -> Widget n
str String
"Save"

  statusBox :: Widget n
statusBox = forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall n. Widget n
emptyWidget forall n. String -> Widget n
str forall a b. (a -> b) -> a -> b
$ WorldEditor Name
worldEditor forall s a. s -> Getting a s a -> a
^. forall n. Lens' (WorldEditor n) (Maybe String)
lastWorldEditorMessage

drawLabeledEntitySwatch :: EntityFacade -> Widget Name
drawLabeledEntitySwatch :: EntityFacade -> Widget Name
drawLabeledEntitySwatch (EntityFacade EntityName
eName Display
eDisplay) =
  forall n. Widget n
tile forall n. Widget n -> Widget n -> Widget n
<+> forall n. EntityName -> Widget n
txt EntityName
eName
 where
  tile :: Widget n
tile = forall n. Padding -> Widget n -> Widget n
padRight (Int -> Padding
Pad Int
1) forall a b. (a -> b) -> a -> b
$ forall n. Display -> Widget n
renderDisplay Display
eDisplay

drawTerrainSelector :: AppState -> Widget Name
drawTerrainSelector :: AppState -> Widget Name
drawTerrainSelector AppState
s =
  forall n. Int -> Widget n -> Widget n
padAll Int
1
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {n}. Widget n -> Widget n
hCenter
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. Int -> Widget n -> Widget n
vLimit (forall (t :: * -> *) a. Foldable t => t a -> Int
length (forall e. (Enum e, Bounded e) => [e]
listEnums :: [TerrainType]))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) n e.
(Traversable t, Splittable t, Ord n, Show n) =>
(Int -> Bool -> e -> Widget n)
-> Bool -> GenericList n t e -> Widget n
BL.renderListWithIndex Int -> Bool -> TerrainType -> Widget Name
listDrawTerrainElement Bool
True
    forall a b. (a -> b) -> a -> b
$ AppState
s forall s a. s -> Getting a s a -> a
^. Lens' AppState UIState
uiState forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens' UIState (WorldEditor Name)
uiWorldEditor forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. Lens' (WorldEditor n) (List n TerrainType)
terrainList

listDrawTerrainElement :: Int -> Bool -> TerrainType -> Widget Name
listDrawTerrainElement :: Int -> Bool -> TerrainType -> Widget Name
listDrawTerrainElement Int
pos Bool
_isSelected TerrainType
a =
  forall n. Ord n => n -> Widget n -> Widget n
clickable (Int -> Name
TerrainListItem Int
pos) forall a b. (a -> b) -> a -> b
$ TerrainType -> Widget Name
VU.drawLabeledTerrainSwatch TerrainType
a

drawEntityPaintSelector :: AppState -> Widget Name
drawEntityPaintSelector :: AppState -> Widget Name
drawEntityPaintSelector AppState
s =
  forall n. Int -> Widget n -> Widget n
padAll Int
1
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {n}. Widget n -> Widget n
hCenter
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. Int -> Widget n -> Widget n
vLimit Int
10
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) n e.
(Traversable t, Splittable t, Ord n, Show n) =>
(Int -> Bool -> e -> Widget n)
-> Bool -> GenericList n t e -> Widget n
BL.renderListWithIndex Int -> Bool -> EntityFacade -> Widget Name
listDrawEntityPaintElement Bool
True
    forall a b. (a -> b) -> a -> b
$ AppState
s forall s a. s -> Getting a s a -> a
^. Lens' AppState UIState
uiState forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens' UIState (WorldEditor Name)
uiWorldEditor forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. Lens' (WorldEditor n) (List n EntityFacade)
entityPaintList

listDrawEntityPaintElement :: Int -> Bool -> EntityFacade -> Widget Name
listDrawEntityPaintElement :: Int -> Bool -> EntityFacade -> Widget Name
listDrawEntityPaintElement Int
pos Bool
_isSelected EntityFacade
a =
  forall n. Ord n => n -> Widget n -> Widget n
clickable (Int -> Name
EntityPaintListItem Int
pos) forall a b. (a -> b) -> a -> b
$ EntityFacade -> Widget Name
drawLabeledEntitySwatch EntityFacade
a