{-# LANGUAGE TemplateHaskell #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- A small custom "panel widget" for use in the Swarm TUI. Panels draw
-- a border around some content, with the color of the border
-- depending on whether the panel is currently focused.  Panels exist
-- within a 'FocusRing' such that the user can cycle between the
-- panels (using /e.g./ the @Tab@ key).  Panels can also have labels
-- at up to 6 locations (top\/bottom, left\/center\/right).
module Swarm.TUI.Panel (
  panel,
) where

import Brick
import Brick.Focus
import Brick.Widgets.Border
import Control.Lens
import Swarm.TUI.Border
import Swarm.Util (applyWhen)

data Panel n = Panel
  {forall n. Panel n -> n
_panelName :: n, forall n. Panel n -> BorderLabels n
_panelLabels :: BorderLabels n, forall n. Panel n -> Widget n
_panelContent :: Widget n}

makeLenses ''Panel

instance Named (Panel n) n where
  getName :: Panel n -> n
getName = Getting n (Panel n) n -> Panel n -> n
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting n (Panel n) n
forall n (f :: * -> *).
Functor f =>
(n -> f n) -> Panel n -> f (Panel n)
panelName

drawPanel :: Eq n => AttrName -> FocusRing n -> Panel n -> Widget n
drawPanel :: forall n. Eq n => AttrName -> FocusRing n -> Panel n -> Widget n
drawPanel AttrName
attr FocusRing n
fr = FocusRing n -> (Bool -> Panel n -> Widget n) -> Panel n -> Widget n
forall n a b.
(Eq n, Named a n) =>
FocusRing n -> (Bool -> a -> b) -> a -> b
withFocusRing FocusRing n
fr Bool -> Panel n -> Widget n
forall n. Bool -> Panel n -> Widget n
drawPanel'
 where
  drawPanel' :: Bool -> Panel n -> Widget n
  drawPanel' :: forall n. Bool -> Panel n -> Widget n
drawPanel' Bool
focused Panel n
p =
    Bool -> (Widget n -> Widget n) -> Widget n -> Widget n
forall a. Bool -> (a -> a) -> a -> a
applyWhen Bool
focused (AttrName -> AttrName -> Widget n -> Widget n
forall n. AttrName -> AttrName -> Widget n -> Widget n
overrideAttr AttrName
borderAttr AttrName
attr) (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$
      BorderLabels n -> Widget n -> Widget n
forall n. BorderLabels n -> Widget n -> Widget n
borderWithLabels (Panel n
p Panel n
-> Getting (BorderLabels n) (Panel n) (BorderLabels n)
-> BorderLabels n
forall s a. s -> Getting a s a -> a
^. Getting (BorderLabels n) (Panel n) (BorderLabels n)
forall n (f :: * -> *).
Functor f =>
(BorderLabels n -> f (BorderLabels n)) -> Panel n -> f (Panel n)
panelLabels) (Panel n
p Panel n -> Getting (Widget n) (Panel n) (Widget n) -> Widget n
forall s a. s -> Getting a s a -> a
^. Getting (Widget n) (Panel n) (Widget n)
forall n (f :: * -> *).
Functor f =>
(Widget n -> f (Widget n)) -> Panel n -> f (Panel n)
panelContent)

-- | Create a panel.
panel ::
  Eq n =>
  -- | Border attribute to use when the panel is focused.
  AttrName ->
  -- | Focus ring the panel should be part of.
  FocusRing n ->
  -- | The name of the panel. Must be unique.
  n ->
  -- | The labels to use around the border.
  BorderLabels n ->
  -- | The content of the panel.
  Widget n ->
  Widget n
panel :: forall n.
Eq n =>
AttrName
-> FocusRing n -> n -> BorderLabels n -> Widget n -> Widget n
panel AttrName
attr FocusRing n
fr n
nm BorderLabels n
labs Widget n
w = AttrName -> FocusRing n -> Panel n -> Widget n
forall n. Eq n => AttrName -> FocusRing n -> Panel n -> Widget n
drawPanel AttrName
attr FocusRing n
fr (n -> BorderLabels n -> Widget n -> Panel n
forall n. n -> BorderLabels n -> Widget n -> Panel n
Panel n
nm BorderLabels n
labs Widget n
w)