{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

{-| This package provides an overlay library for Brick that allows
  individual TUI screen areas to be independently developed and then easily
  composed into the overall application.
-}

module Brick.Panes
  (
    -- * Pane Specification
    -- ** Definition and Initialization
    Pane
  , PaneState
  , InitConstraints
  , initPaneState
    -- ** Drawing
  , DrawConstraints
  , drawPane
    -- ** Event Handling
  , EventConstraints
  , EventType
  , DispatchEvent
  , focusable
  , handlePaneEvent
    -- ** Updating the Pane's state
  , UpdateType
  , updatePane
    -- ** Focus management helpers and constraints
  , focus1If
  , HasFocus
  , getFocus
  , Focused(Focused)
  , focused
    -- * Panel Specification
    -- ** Definition and Initialization
  , Panel
  , basePanel
  , addToPanel
  , PaneFocus( Always, Never, WhenFocused, WhenFocusedModal
             , WhenFocusedModalHandlingAllEvents
             )
    -- ** Pane and base state access
  , onPane
  , onBaseState
    -- ** Drawing
  , panelDraw
    -- ** Focus and Event management
  , handleFocusAndPanelEvents
  , focusRingUpdate
  , isPanelModal
  , enteredModal
  , exitedModal
  , PanelMode(Normal, Modal)
  , PanelTransition
    -- ** Access and operations
  , PanelOps(..)
  , PaneNumber
  )
where

import           Control.Applicative ( (<|>) )
import qualified Data.Foldable as F
import           Data.Kind ( Constraint, Type )
import qualified Data.List as L
import           Data.Maybe ( fromMaybe )
import           Data.Sequence ( Seq, (><) )
import qualified Data.Sequence as Seq
import           Data.Type.Equality
import           Data.Void ( Void, absurd )
import           GHC.TypeLits
import qualified Graphics.Vty as Vty
import           Lens.Micro
#if !MIN_VERSION_base(4,16,0)
-- starting in base 4.16.0.0, GHC.TypeLits exports Natural
import           Numeric.Natural ( Natural )
#endif

import           Brick
import           Brick.Focus


-- | Class to manage each pane in the Brick TUI.
--
-- Type parameters:
--
--  *  @pane@ = Pane Type, uniquely identifying this pane
--  *  @appEv@ = The application's event type
--  *  @n@ = Widget type parameter
--
-- The 'PaneState' specifies the state that should be stored globally
-- and which provides the primary information for handling this pane
-- (for both draw and event handling operations).
--
-- The 'initPaneState' method is responsible for returning an initial 'PaneState'
-- value (at startup).
--
-- The 'drawPane' method is called to render the pane into a 'Widget' (or Nothing
-- if this Pane should not currently be drawn).  It is passed the 'PaneState' and
-- also a drawing parameter.  The 'DrawConstraints' can be used to specify
-- additional instance requirements for the drawing parameter.  The global
-- application state is often passed as this drawing parameter, but the
-- 'drawPane' method should only perform 'DrawConstraints' operations, along with
-- general Brick drawing operations.
--
-- The 'focusable' method should return the names of the widgets that can be the
-- target of the 'FocusRing' in the current state.  This should always return an
-- empty list if the 'drawPane' returns 'Nothing'.
--
-- The 'handlePaneEvent' method is called to handle an event that has occurred
-- within this Pane.  It should return the updated 'PaneState' in the context of
-- an 'EventM' monadic operation.
--
-- The 'updatePane' method is called with the 'UpdateType' to perform any
-- updating of the 'PaneState' from the update type data.
class Pane n appEv pane | pane -> n where

  -- | State information associated with this pane
  data (PaneState pane appEv)

  -- | Type of data provided to updatePane
  type (UpdateType pane)

  -- | Constraints on argument passed to 'initPaneState'.  If there are no
  -- constraints, this may be specified as @()@, or simply omitted because @()@
  -- is the default.
  type (InitConstraints pane initctxt) :: Constraint
  -- | Function called to initialize the internal 'PaneState'
  initPaneState :: (InitConstraints pane i) => i -> PaneState pane appEv

  -- | Constraints on the @drawcontext@ parameter passed to 'drawPane'.
  type (DrawConstraints pane drwctxt n) :: Constraint
  -- | Function called to draw the 'Pane' as a Brick 'Widget', or 'Nothing' if
  -- this 'Pane' should not be drawn at the current time.
  drawPane :: (DrawConstraints pane drawcontext n, Eq n)
           => PaneState pane appEv -> drawcontext -> Maybe (Widget n)

  -- | The constraints that should exist on the 'eventcontext' argment passed to
  -- 'focusable' and 'handlePaneEvent'.
  type (EventConstraints pane evctxt) :: Constraint
  -- | The type of the event argument delivered to 'handlePaneEvent'.  This
  -- should either be 'Vty.Event' or 'BrickEvent', depending on what level of
  -- granularity the 'handlePaneEvent' operates at.
  type (EventType pane n appEv)
  -- | The 'focusable' method is called to determine which Widget targets should
  -- be part of the Brick 'FocusRing'.
  focusable :: (EventConstraints pane eventcontext, Eq n)
            => eventcontext -> PaneState pane appEv -> Seq.Seq n
  -- | Called to handle an 'EventType' event for the 'Pane'.  This is typically
  -- only called when (one of the 'focusable' targets of) the 'Pane' is the focus
  -- of the 'FocusRing'.  It should modify the internal 'PaneState' as
  -- appropriate and make any appropriate changes to properly render the 'Pane'
  -- on the next 'drawPane' call.
  --
  -- Note that this function also receives an eventcontext which it may stipulate
  -- constraints on.  Those constraints should be *read-only* constraints.  This
  -- is especially important when the pane is used as part of a panel: the Panel
  -- itself is passed as the eventcontext, but the panel may not be modified
  -- because the panel event dispatching will discard any changes on completion.
  handlePaneEvent :: (EventConstraints pane eventcontext, Eq n)
                  => eventcontext
                  -> EventType pane n appEv
                  -> PaneState pane appEv
                  -> EventM n es (PaneState pane appEv)
  -- | Function called to update the internal 'PaneState', using the passed
  -- 'updateType' argument.
  updatePane :: UpdateType pane
             -> PaneState pane appEv
             -> PaneState pane appEv

  -- A set of defaults that allows a minimal instance specification
  type (UpdateType pane) = ()
  type (InitConstraints pane initctxt) = ()
  type (DrawConstraints pane drwctxt n) = ()
  type (EventConstraints pane evctxt) = ()
  type (EventType pane n appev) = Vty.Event  -- by default, handle Vty events
  focusable eventcontext
_ PaneState pane appEv
_ = forall a. Monoid a => a
mempty
  handlePaneEvent eventcontext
_ EventType pane n appEv
_ = forall (m :: * -> *) a. Monad m => a -> m a
return
  updatePane UpdateType pane
_ = forall a. a -> a
id


-- | This is a helper function for a Pane with a single Widget name and a
-- conditional focus.  For example, if a widget is always focusable, then it can
-- specify:
--
--  > instance Pane N E ThisPane () where
--  >   ...
--  >   focusable _ = const $ focus1If MyWidgetName True
focus1If :: n -> Bool -> Seq.Seq n
focus1If :: forall n. n -> Bool -> Seq n
focus1If n
n Bool
b = if Bool
b then forall a. a -> Seq a
Seq.singleton n
n else forall a. Monoid a => a
mempty


-- | This class allows retrieval of the current focused Widget (if any).  This
-- class is frequently specified as one of the constraints for the
-- 'DrawConstraints' or 'EventConstraints' of a 'Pane'.
class HasFocus b n | b -> n where
  -- | Provides a lens from the primary type to the 'Focused' type, which
  -- specifies the current focused element (if any).
  getFocus :: Lens' b (Focused n)
  -- By default, nothing has Focus
  getFocus Focused n -> f (Focused n)
f b
x = forall a b. a -> b -> a
const b
x forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Focused n -> f (Focused n)
f (forall n. Maybe n -> Focused n
Focused forall a. Maybe a
Nothing)

-- | This is a newtype to wrap the identification of the current focused element
-- (if any).
newtype Focused n = Focused { forall n. Focused n -> Maybe n
focused :: Maybe n
                              -- ^ The current focused element or 'Nothing'.
                            }


-- | The 'DispatchEvent' class is used to determine which type of event to
-- dispatch to a 'Pane' by selecting on the @'EventType' pane n@.  This is used
-- internally in the brick-panes implementation and client code does not need to
-- explicitly specify instances of this class.
class DispatchEvent n appev pane evtype where
  dispEv :: ( Pane n appev pane
            , EventConstraints pane base
            , Eq n
            )
         => EventType pane n appev :~: evtype
         -> base -> BrickEvent n appev -> PaneState pane appev
         -> EventM n es (PaneState pane appev)

instance DispatchEvent n appev pane (BrickEvent n appev) where
  dispEv :: forall base es.
(Pane n appev pane, EventConstraints pane base, Eq n) =>
(EventType pane n appev :~: BrickEvent n appev)
-> base
-> BrickEvent n appev
-> PaneState pane appev
-> EventM n es (PaneState pane appev)
dispEv EventType pane n appev :~: BrickEvent n appev
Refl base
base BrickEvent n appev
ev PaneState pane appev
s = forall n appEv pane eventcontext es.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext
-> EventType pane n appEv
-> PaneState pane appEv
-> EventM n es (PaneState pane appEv)
handlePaneEvent base
base BrickEvent n appev
ev PaneState pane appev
s

instance DispatchEvent n appev pane Vty.Event where
  dispEv :: forall base es.
(Pane n appev pane, EventConstraints pane base, Eq n) =>
(EventType pane n appev :~: Event)
-> base
-> BrickEvent n appev
-> PaneState pane appev
-> EventM n es (PaneState pane appev)
dispEv EventType pane n appev :~: Event
Refl base
base BrickEvent n appev
ev PaneState pane appev
s = case BrickEvent n appev
ev of
    VtyEvent Event
vev -> forall n appEv pane eventcontext es.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext
-> EventType pane n appEv
-> PaneState pane appEv
-> EventM n es (PaneState pane appEv)
handlePaneEvent base
base Event
vev PaneState pane appev
s
    BrickEvent n appev
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return PaneState pane appev
s


----------------------------------------------------------------------
-- A Panel is a composite of a number of panes

-- | A Panel is a recursive data sequence of individual 'Pane' elements
-- with a core state.  The core state represents the base state of the
-- Brick application, independent of the various Pane data.  Each 'Pane'
-- has an instance that defines its 'PaneState', which is associated
-- here with a potential Widget name (allowing selected actions; see
-- 'handleFocusAndPanelEvents').
--
-- The 'Panel' type closes over the 'state' type argument, which is used for all
-- three of the 'Pane' constraints ('DrawConstraints', 'EventConstraints', and
-- indirectly the 'InitConstraints'), which means that the same 'state' type must
-- be passed to all three associated Pane methods; a 'Pane' used outside of the
-- 'Panel' container is not constrained in this manner and each method could have
-- a different argument.  For the Panel, the 'state' is typically the Panel
-- "beneath" the current Pane, which is the aggregate of the base state and all
-- Panes added before the current pane.
data Panel n appev state (panes :: [Type]) where
  Panel :: state -> Panel n appev state '[]
  PanelWith :: ( Pane n appev pane
               , DrawConstraints pane (Panel n appev state panes) n
               , EventConstraints pane (Panel n appev state panes)
               , DispatchEvent n appev pane (EventType pane n appev)
               )
            => PaneState pane appev -> PaneFocus n
            -> Panel n appev state panes -> Panel n appev state (pane ': panes)


-- | This is the base constructor for Panel that is given the core
-- application state.
basePanel :: state -> Panel n appev state '[]
basePanel :: forall state n appev. state -> Panel n appev state '[]
basePanel = forall state n appev. state -> Panel n appev state '[]
Panel


-- | Each 'Pane' that is part of the 'Panel' should be added to the 'Panel' via
-- this function, which also specifies when the `Pane` should receive Events.
addToPanel :: Pane n appev pane
           => InitConstraints pane (Panel n appev state panes)
           => DrawConstraints pane (Panel n appev state panes) n
           => EventConstraints pane (Panel n appev state panes)
           => DispatchEvent n appev pane (EventType pane n appev)
           => PaneFocus n
           -> Panel n appev state panes
           -> Panel n appev state (pane ': panes)
addToPanel :: forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 InitConstraints pane (Panel n appev state panes),
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneFocus n
-> Panel n appev state panes -> Panel n appev state (pane : panes)
addToPanel PaneFocus n
n Panel n appev state panes
pnl = forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith (forall n appEv pane i.
(Pane n appEv pane, InitConstraints pane i) =>
i -> PaneState pane appEv
initPaneState Panel n appev state panes
pnl) PaneFocus n
n Panel n appev state panes
pnl


-- | Specifies when a Pane should receive events.
data PaneFocus n =
  -- | Indicates that this Pane always receives all events, although it is never
  --   part of a focus ring.  This should be used for Widgets that have a global
  --   event handling.
  Always
  -- | Indicates that this Pane's handlePaneEvent is never called
  | Never
  -- | Indicates that the pane should receive events when the current focus is
  --   equal to a 'focusable' return from the Pane.
  | WhenFocused
  -- | Indicates that the pane should receive events when the current focus is
  --   equal to a 'focusable' return from the Pane, and that this should block
  --   all non-modal focus candidates (it is expected that there is only one
  --   modal, but this is not required).
  | WhenFocusedModal
  | WhenFocusedModal' (FocusRing n)  -- previous focus ring to return to
  -- | Indicates that the pane should receive events when the current focus is
  -- equal to a 'focusable' return from the Pane, and that this should block all
  -- non-modal focus candidates, just as with 'WhenFocusedModal'.  However, this
  -- also sends *all* events to the modal Pane instead of the normal 'Panel'
  -- handling of events (e.g.  @TAB@/@Shift-TAB@).
  | WhenFocusedModalHandlingAllEvents
  | WhenFocusedModalHandlingAllEvents' (FocusRing n)  -- previous focus ring


-- | If the base state provides Focus information, then the Panel can provide
-- focus information.
instance HasFocus appState n => HasFocus (Panel n appEv appState panes) n where
  getFocus :: Lens' (Panel n appEv appState panes) (Focused n)
getFocus = forall n appev state (panes :: [*]).
Lens' (Panel n appev state panes) state
onBaseState forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b n. HasFocus b n => Lens' b (Focused n)
getFocus


-- | This is a lens providing access to the base application state at
-- the core of the Panel.
onBaseState :: Lens' (Panel n appev state panes) state
onBaseState :: forall n appev state (panes :: [*]).
Lens' (Panel n appev state panes) state
onBaseState state -> f state
f (Panel state
s) = forall state n appev. state -> Panel n appev state '[]
Panel forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> state -> f state
f state
s
onBaseState state -> f state
f (PanelWith PaneState pane appev
p PaneFocus n
n Panel n appev state panes
i) = forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
p PaneFocus n
n forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall n appev state (panes :: [*]).
Lens' (Panel n appev state panes) state
onBaseState state -> f state
f Panel n appev state panes
i

-- | This is a lens providing access to the PaneState for a specific Pane in the
-- Panel.  The Pane is typically specified via a type application
-- (e.g. @@MyPane@).
onPane :: forall pane n appev state panes .
          PanelOps pane n appev panes state
       => Lens' (Panel n appev state panes) (PaneState pane appev)
onPane :: forall pane n appev state (panes :: [*]).
PanelOps pane n appev panes state =>
Lens' (Panel n appev state panes) (PaneState pane appev)
onPane = forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens (forall pane n appev (panes :: [*]) s.
PanelOps pane n appev panes s =>
Panel n appev s panes -> PaneState pane appev
panelState @pane) (forall pane n appev (panes :: [*]) s.
PanelOps pane n appev panes s =>
Panel n appev s panes
-> PaneState pane appev -> Panel n appev s panes
panelStateUpdate @pane)


-- -- | This can be used to get the inner Pane from the current Pane in the state.
-- onNextPane :: Lens' (Panel n appev state (pane ': panes)) (Panel n appev state panes)
-- onNextPane f = \case
--   PanelWith a b r -> (\r' -> PanelWith a b r') <$> f r


-- | This class defines the various operations that can be performed
-- on a Panel.  Most of these operations specify a particular Pane as
-- the target of the operation; the operation is performed on that
-- pane and the Panel is is updated with the result.
--
-- The user of this library will not need to develop new instances of this class:
-- the instances defined internally are sufficient.  Users may need to specify
-- 'PanelOps' constraints on various functions.
class PanelOps pane n appev panes s | pane -> n where

  -- | This is called to pass the VTY Event to the specified Pane's
  -- handler with a Panel.
  handlePanelEvent :: (EventConstraints pane s, Eq n)
                   => s -> pane -> Panel n appev s panes -> BrickEvent n appev
                   -> EventM n es (Panel n appev s panes)

  -- | This is used to obtain the state of a specific Pane within the Panel.  The
  -- pane is usually specified by a type application (e.g. @@MyPane@).
  panelState :: Panel n appev s panes -> PaneState pane appev

  -- | This is used to update the state of a specific Pane within the Panel. The
  -- pane is usually specified by a type application (e.g. @@MyPane@).
  panelStateUpdate :: Panel n appev s panes -> PaneState pane appev
                   -> Panel n appev s panes

  -- | This returns an ordinal index of the pane within the panel.
  paneNumber :: Panel n appev s panes -> PaneNumber


instance (Pane n appev pane) => PanelOps pane n appev (pane ': panes) s where
  handlePanelEvent :: forall es.
(EventConstraints pane s, Eq n) =>
s
-> pane
-> Panel n appev s (pane : panes)
-> BrickEvent n appev
-> EventM n es (Panel n appev s (pane : panes))
handlePanelEvent s
s pane
_p (PanelWith PaneState pane appev
pd PaneFocus n
n Panel n appev s panes
r) BrickEvent n appev
ev =
    (\PaneState pane appev
pd' -> forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
pd' PaneFocus n
n Panel n appev s panes
r) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall n appev pane evtype base es.
(DispatchEvent n appev pane evtype, Pane n appev pane,
 EventConstraints pane base, Eq n) =>
(EventType pane n appev :~: evtype)
-> base
-> BrickEvent n appev
-> PaneState pane appev
-> EventM n es (PaneState pane appev)
dispEv forall {k} (a :: k). a :~: a
Refl s
s BrickEvent n appev
ev PaneState pane appev
pd
  panelState :: Panel n appev s (pane : panes) -> PaneState pane appev
panelState (PanelWith PaneState pane appev
pd PaneFocus n
_ Panel n appev s panes
_) = PaneState pane appev
pd
  panelStateUpdate :: Panel n appev s (pane : panes)
-> PaneState pane appev -> Panel n appev s (pane : panes)
panelStateUpdate (PanelWith PaneState pane appev
_pd PaneFocus n
n Panel n appev s panes
r) = \PaneState pane appev
pd' -> forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
pd' PaneFocus n
n Panel n appev s panes
r
  paneNumber :: Panel n appev s (pane : panes) -> PaneNumber
paneNumber Panel n appev s (pane : panes)
_ = Natural -> PaneNumber
PaneNo Natural
0


instance {-# OVERLAPPABLE #-} (PanelOps pane n appev panes s) =>
  PanelOps pane n appev (o ': panes) s where
  handlePanelEvent :: forall es.
(EventConstraints pane s, Eq n) =>
s
-> pane
-> Panel n appev s (o : panes)
-> BrickEvent n appev
-> EventM n es (Panel n appev s (o : panes))
handlePanelEvent s
s pane
p (PanelWith PaneState pane appev
pd PaneFocus n
n Panel n appev s panes
r) BrickEvent n appev
ev =
    forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
pd PaneFocus n
n forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall pane n appev (panes :: [*]) s es.
(PanelOps pane n appev panes s, EventConstraints pane s, Eq n) =>
s
-> pane
-> Panel n appev s panes
-> BrickEvent n appev
-> EventM n es (Panel n appev s panes)
handlePanelEvent s
s pane
p Panel n appev s panes
r BrickEvent n appev
ev
  panelState :: Panel n appev s (o : panes) -> PaneState pane appev
panelState (PanelWith PaneState pane appev
_ PaneFocus n
_ Panel n appev s panes
r) = forall pane n appev (panes :: [*]) s.
PanelOps pane n appev panes s =>
Panel n appev s panes -> PaneState pane appev
panelState Panel n appev s panes
r
  panelStateUpdate :: Panel n appev s (o : panes)
-> PaneState pane appev -> Panel n appev s (o : panes)
panelStateUpdate (PanelWith PaneState pane appev
pd PaneFocus n
n Panel n appev s panes
r) =
    \PaneState pane appev
pd' -> forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
pd PaneFocus n
n forall a b. (a -> b) -> a -> b
$ forall pane n appev (panes :: [*]) s.
PanelOps pane n appev panes s =>
Panel n appev s panes
-> PaneState pane appev -> Panel n appev s panes
panelStateUpdate Panel n appev s panes
r PaneState pane appev
pd'
  paneNumber :: Panel n appev s (o : panes) -> PaneNumber
paneNumber (PanelWith PaneState pane appev
_ PaneFocus n
_ Panel n appev s panes
r) = forall a. Enum a => a -> a
succ forall a b. (a -> b) -> a -> b
$ forall pane n appev (panes :: [*]) s.
PanelOps pane n appev panes s =>
Panel n appev s panes -> PaneNumber
paneNumber @pane Panel n appev s panes
r


instance ( TypeError
           ('Text "No " ':<>: 'ShowType pane ':<>: 'Text " in Panel"
            ':$$: 'Text "Add this pane to your Panel (or move it lower)"
            ':$$: 'Text "(Possibly driven by DrawConstraints)"
           )
         , Pane n appev pane
         )
  => PanelOps pane n appev '[] s where
  handlePanelEvent :: forall es.
(EventConstraints pane s, Eq n) =>
s
-> pane
-> Panel n appev s '[]
-> BrickEvent n appev
-> EventM n es (Panel n appev s '[])
handlePanelEvent = forall a. Void -> a
absurd (forall a. HasCallStack => a
undefined :: Void)
  panelState :: Panel n appev s '[] -> PaneState pane appev
panelState = forall a. Void -> a
absurd (forall a. HasCallStack => a
undefined :: Void)
  panelStateUpdate :: Panel n appev s '[] -> PaneState pane appev -> Panel n appev s '[]
panelStateUpdate = forall a. Void -> a
absurd (forall a. HasCallStack => a
undefined :: Void)
  paneNumber :: Panel n appev s '[] -> PaneNumber
paneNumber = forall a. Void -> a
absurd (forall a. HasCallStack => a
undefined :: Void)


-- | Called to draw a specific pane in the panel.  Typically invoked from the
-- applications' global drawing function.
panelDraw :: forall pane n appev s panes .
             ( DrawConstraints pane (Panel n appev s panes) n
             , PanelOps pane n appev panes s
             , Pane n appev pane
             , Eq n
             )
          => Panel n appev s panes -> Maybe (Widget n)
panelDraw :: forall pane n appev s (panes :: [*]).
(DrawConstraints pane (Panel n appev s panes) n,
 PanelOps pane n appev panes s, Pane n appev pane, Eq n) =>
Panel n appev s panes -> Maybe (Widget n)
panelDraw Panel n appev s panes
panel = forall n appEv pane drawcontext.
(Pane n appEv pane, DrawConstraints pane drawcontext n, Eq n) =>
PaneState pane appEv -> drawcontext -> Maybe (Widget n)
drawPane (forall pane n appev (panes :: [*]) s.
PanelOps pane n appev panes s =>
Panel n appev s panes -> PaneState pane appev
panelState @pane Panel n appev s panes
panel) Panel n appev s panes
panel


-- | Called to dispatch an events to the focused Pane in the Panel as determined
-- by matching the Widget names returned by the Pane's 'focusable' with the
-- current FocusRing focus target.
handlePanelEvents :: Eq n
                  => Panel n appev s panes
                  -> BrickEvent n appev
                  -> Focused n
                  -> EventM n es (Panel n appev s panes)
handlePanelEvents :: forall n appev s (panes :: [*]) es.
Eq n =>
Panel n appev s panes
-> BrickEvent n appev
-> Focused n
-> EventM n es (Panel n appev s panes)
handlePanelEvents Panel n appev s panes
panel BrickEvent n appev
ev (Focused Maybe n
focus) =
  -- n.b. no need to check focusable for a pane because an invisible
  -- pane should never have focus
  case Maybe n
focus of
    Maybe n
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return Panel n appev s panes
panel
    Just n
fcs -> forall n appev s (panes :: [*]) es.
Eq n =>
n
-> Panel n appev s panes
-> BrickEvent n appev
-> EventM n es (Panel n appev s panes)
go n
fcs Panel n appev s panes
panel BrickEvent n appev
ev
  where
    go :: Eq n
       => n -> Panel n appev s panes -> BrickEvent n appev
       -> EventM n es (Panel n appev s panes)
    go :: forall n appev s (panes :: [*]) es.
Eq n =>
n
-> Panel n appev s panes
-> BrickEvent n appev
-> EventM n es (Panel n appev s panes)
go n
_ p :: Panel n appev s panes
p@(Panel {}) BrickEvent n appev
_ = forall (m :: * -> *) a. Monad m => a -> m a
return Panel n appev s panes
p
    go n
fcs (PanelWith PaneState pane appev
pd PaneFocus n
pf Panel n appev s panes
r) BrickEvent n appev
evnt =
      let handleIt :: EventM n es (PaneState pane appev)
handleIt = forall n appev pane evtype base es.
(DispatchEvent n appev pane evtype, Pane n appev pane,
 EventConstraints pane base, Eq n) =>
(EventType pane n appev :~: evtype)
-> base
-> BrickEvent n appev
-> PaneState pane appev
-> EventM n es (PaneState pane appev)
dispEv forall {k} (a :: k). a :~: a
Refl Panel n appev s panes
r BrickEvent n appev
evnt PaneState pane appev
pd
          skipIt :: EventM n es (PaneState pane appev)
skipIt = forall (m :: * -> *) a. Monad m => a -> m a
return PaneState pane appev
pd
      in do PaneState pane appev
pd' <- case PaneFocus n
pf of
                     PaneFocus n
Never -> EventM n es (PaneState pane appev)
skipIt
                     PaneFocus n
Always -> EventM n es (PaneState pane appev)
handleIt
                     PaneFocus n
WhenFocused -> if n
fcs forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd
                                    then EventM n es (PaneState pane appev)
handleIt
                                    else EventM n es (PaneState pane appev)
skipIt
                     PaneFocus n
WhenFocusedModal -> if n
fcs forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd
                                         then EventM n es (PaneState pane appev)
handleIt
                                         else EventM n es (PaneState pane appev)
skipIt
                     WhenFocusedModal' FocusRing n
_ -> if n
fcs forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd
                                            then EventM n es (PaneState pane appev)
handleIt
                                            else EventM n es (PaneState pane appev)
skipIt
                     PaneFocus n
WhenFocusedModalHandlingAllEvents ->
                       if n
fcs forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd
                       then EventM n es (PaneState pane appev)
handleIt
                       else EventM n es (PaneState pane appev)
skipIt
                     WhenFocusedModalHandlingAllEvents' FocusRing n
_ ->
                       if n
fcs forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd
                       then EventM n es (PaneState pane appev)
handleIt
                       else EventM n es (PaneState pane appev)
skipIt
            forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
pd' PaneFocus n
pf forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall n appev s (panes :: [*]) es.
Eq n =>
n
-> Panel n appev s panes
-> BrickEvent n appev
-> EventM n es (Panel n appev s panes)
go n
fcs Panel n appev s panes
r BrickEvent n appev
evnt


-- | Called to handle events for the entire 'Panel', including focus-changing
-- events.  The current focused 'Pane' is determined and that Pane's handler is
-- called (based on the 'Widget' names returned as 'focusable' for that Pane).
-- If a Pane has no associated Widget name (the 'PaneFocus' value is specified as
-- 'Nothing' when adding the Pane to the Panel) then its handler is never called.
--
-- This function returns the updated Panel state, as well as an indication of
-- whether a modal transition occured while handling the event.
--
-- This function manages updating the focus when @Tab@ or @Shift-Tab@ is
-- selected, except when the currently focused pane was created with the
-- 'WhenFocusedModalHandlingAllEvents', in which case all events are passed
-- through to the Pane.
handleFocusAndPanelEvents :: Eq n => Ord n
                          => Lens' (Panel n appev s panes) (FocusRing n)
                          -> Panel n appev s panes
                          -> BrickEvent n appev
                          -> EventM n es (PanelTransition, Panel n appev s panes)
handleFocusAndPanelEvents :: forall n appev s (panes :: [*]) es.
(Eq n, Ord n) =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes
-> BrickEvent n appev
-> EventM n es (PanelTransition, Panel n appev s panes)
handleFocusAndPanelEvents Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
panel =
  let fcs :: Maybe n
fcs = forall n. FocusRing n -> Maybe n
focusGetCurrent (Panel n appev s panes
panel forall s a. s -> Getting a s a -> a
^. Lens' (Panel n appev s panes) (FocusRing n)
focusL)
      doPanelEvHandling :: Bool
doPanelEvHandling = case Maybe n
fcs of
                            Maybe n
Nothing -> Bool
True
                            Just n
curFcs -> forall n appev s (panes :: [*]).
Eq n =>
n -> Panel n appev s panes -> Bool
chkEv n
curFcs Panel n appev s panes
panel
  in \case
    VtyEvent (Vty.EvKey (Vty.KChar Char
'\t') []) | Bool
doPanelEvHandling ->
      forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. Maybe a
Nothing, Panel n appev s panes
panel forall a b. a -> (a -> b) -> b
& Lens' (Panel n appev s panes) (FocusRing n)
focusL forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ forall n. FocusRing n -> FocusRing n
focusNext)
    VtyEvent (Vty.EvKey Key
Vty.KBackTab []) | Bool
doPanelEvHandling ->
      forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. Maybe a
Nothing, Panel n appev s panes
panel forall a b. a -> (a -> b) -> b
& Lens' (Panel n appev s panes) (FocusRing n)
focusL forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ forall n. FocusRing n -> FocusRing n
focusPrev)
    BrickEvent n appev
panelEv -> do
      Panel n appev s panes
u <- forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes -> Panel n appev s panes
focusRingUpdate Lens' (Panel n appev s panes) (FocusRing n)
focusL forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall n appev s (panes :: [*]) es.
Eq n =>
Panel n appev s panes
-> BrickEvent n appev
-> Focused n
-> EventM n es (Panel n appev s panes)
handlePanelEvents Panel n appev s panes
panel BrickEvent n appev
panelEv (forall n. Maybe n -> Focused n
Focused Maybe n
fcs)
      let fcs' :: Maybe n
fcs' = forall n. FocusRing n -> Maybe n
focusGetCurrent (Panel n appev s panes
u forall s a. s -> Getting a s a -> a
^. Lens' (Panel n appev s panes) (FocusRing n)
focusL)
      if Maybe n
fcs forall a. Eq a => a -> a -> Bool
== Maybe n
fcs'
        then forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. Maybe a
Nothing, Panel n appev s panes
u)
        else let m0 :: PanelMode
m0 = forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes -> PanelMode
panelMode Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
panel
                 m1 :: PanelMode
m1 = forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes -> PanelMode
panelMode Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
u
             in forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ if PanelMode
m0 forall a. Eq a => a -> a -> Bool
== PanelMode
m1
                         then (forall a. Maybe a
Nothing, Panel n appev s panes
u)
                         else (forall a. a -> Maybe a
Just (PanelMode
m0, PanelMode
m1), Panel n appev s panes
u)
  where
    chkEv :: Eq n => n -> Panel n appev s panes -> Bool
    chkEv :: forall n appev s (panes :: [*]).
Eq n =>
n -> Panel n appev s panes -> Bool
chkEv n
curFcs = \case
      Panel {} -> Bool
True
      PanelWith PaneState pane appev
pd PaneFocus n
WhenFocusedModalHandlingAllEvents Panel n appev s panes
r ->
        (Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ n
curFcs forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd) Bool -> Bool -> Bool
&& forall n appev s (panes :: [*]).
Eq n =>
n -> Panel n appev s panes -> Bool
chkEv n
curFcs Panel n appev s panes
r
      PanelWith PaneState pane appev
pd (WhenFocusedModalHandlingAllEvents' FocusRing n
_) Panel n appev s panes
r ->
        (Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ n
curFcs forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd) Bool -> Bool -> Bool
&& forall n appev s (panes :: [*]).
Eq n =>
n -> Panel n appev s panes -> Bool
chkEv n
curFcs Panel n appev s panes
r
      PanelWith PaneState pane appev
_ PaneFocus n
_ Panel n appev s panes
r -> forall n appev s (panes :: [*]).
Eq n =>
n -> Panel n appev s panes -> Bool
chkEv n
curFcs Panel n appev s panes
r


panelMode :: Eq n
          => Ord n
          => Lens' (Panel n appev s panes) (FocusRing n)
          -> Panel n appev s panes -> PanelMode
panelMode :: forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes -> PanelMode
panelMode Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
panel =
  forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
[n] -> Panel n appev s panes -> PanelMode
modalTgt (forall a. Ord a => [a] -> [a]
L.sort forall a b. (a -> b) -> a -> b
$ forall n. FocusRing n -> [n]
focusRingToList (Panel n appev s panes
panel forall s a. s -> Getting a s a -> a
^. Lens' (Panel n appev s panes) (FocusRing n)
focusL)) Panel n appev s panes
panel
  -- Note that the focusL-retrieved focus rings (m0, at least)
  -- come from the live previous pane set and may not match the
  -- order of the widget set.  Oddly, it doesn't match a rotation
  -- of the original either, ergo the sorting.
  where
    modalTgt :: Eq n
             => Ord n
             => [n] -> Panel n appev s panes -> PanelMode
    modalTgt :: forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
[n] -> Panel n appev s panes -> PanelMode
modalTgt [n]
fcsRing = \case
      Panel {} -> PanelMode
Normal
      PanelWith PaneState pane appev
pd PaneFocus n
WhenFocusedModal Panel n appev s panes
r ->
        forall n appev s (pnlpanes :: [*]).
(Eq n, Ord n) =>
[n] -> Panel n appev s pnlpanes -> Seq n -> PanelMode
matchOrRecurse [n]
fcsRing Panel n appev s panes
r forall a b. (a -> b) -> a -> b
$ forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd
      PanelWith PaneState pane appev
pd (WhenFocusedModal' FocusRing n
_) Panel n appev s panes
r ->
        forall n appev s (pnlpanes :: [*]).
(Eq n, Ord n) =>
[n] -> Panel n appev s pnlpanes -> Seq n -> PanelMode
matchOrRecurse [n]
fcsRing Panel n appev s panes
r forall a b. (a -> b) -> a -> b
$ forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd
      PanelWith PaneState pane appev
pd PaneFocus n
WhenFocusedModalHandlingAllEvents Panel n appev s panes
r ->
        forall n appev s (pnlpanes :: [*]).
(Eq n, Ord n) =>
[n] -> Panel n appev s pnlpanes -> Seq n -> PanelMode
matchOrRecurse [n]
fcsRing Panel n appev s panes
r forall a b. (a -> b) -> a -> b
$ forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd
      PanelWith PaneState pane appev
pd (WhenFocusedModalHandlingAllEvents' FocusRing n
_) Panel n appev s panes
r ->
        forall n appev s (pnlpanes :: [*]).
(Eq n, Ord n) =>
[n] -> Panel n appev s pnlpanes -> Seq n -> PanelMode
matchOrRecurse [n]
fcsRing Panel n appev s panes
r forall a b. (a -> b) -> a -> b
$ forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd
      PanelWith PaneState pane appev
_ PaneFocus n
_ Panel n appev s panes
r -> case forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
[n] -> Panel n appev s panes -> PanelMode
modalTgt [n]
fcsRing Panel n appev s panes
r of
                           PanelMode
Normal -> PanelMode
Normal
                           Modal PaneNumber
p -> PaneNumber -> PanelMode
Modal forall a b. (a -> b) -> a -> b
$ forall a. Enum a => a -> a
succ PaneNumber
p
    matchOrRecurse :: Eq n => Ord n
                   => [n] -> Panel n appev s pnlpanes -> Seq.Seq n -> PanelMode
    matchOrRecurse :: forall n appev s (pnlpanes :: [*]).
(Eq n, Ord n) =>
[n] -> Panel n appev s pnlpanes -> Seq n -> PanelMode
matchOrRecurse [n]
fcsRing Panel n appev s pnlpanes
r Seq n
f =
      -- if fcsRing `elem` rotations (F.toList f)
      if [n]
fcsRing forall a. Eq a => a -> a -> Bool
== forall a. Ord a => [a] -> [a]
L.sort (forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList Seq n
f)
      then PaneNumber -> PanelMode
Modal (Natural -> PaneNumber
PaneNo Natural
0)
      else case forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
[n] -> Panel n appev s panes -> PanelMode
modalTgt [n]
fcsRing Panel n appev s pnlpanes
r of
             PanelMode
Normal -> PanelMode
Normal
             Modal PaneNumber
p -> PaneNumber -> PanelMode
Modal forall a b. (a -> b) -> a -> b
$ forall a. Enum a => a -> a
succ PaneNumber
p


-- | This function can be called at any time to determine if the Panel is
-- currently displaying a Modal Pane.  This needs the Panel object and a lens
-- that can be used to extract the FocusRing from the Panel.
isPanelModal :: Eq n
            => Ord n
            => Lens' (Panel n appev s panes) (FocusRing n)
            -> Panel n appev s panes
            -> Bool
isPanelModal :: forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes -> Bool
isPanelModal Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
panel = PanelMode
Normal forall a. Eq a => a -> a -> Bool
/= forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes -> PanelMode
panelMode Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
panel


-- | Indicates the current mode of the Panel.  If Modal, the currently active
-- modal Panel is identified by the PaneNumber, which matches the return value of
-- the 'paneNumber' of PanelOps; in general, the use of 'isPaneModal' is
-- recommended over attempting to determine _which_ actual modal pane is active.
data PanelMode = Normal | Modal PaneNumber deriving (PanelMode -> PanelMode -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PanelMode -> PanelMode -> Bool
$c/= :: PanelMode -> PanelMode -> Bool
== :: PanelMode -> PanelMode -> Bool
$c== :: PanelMode -> PanelMode -> Bool
Eq)

-- | Internal bookkeeping to identify a particular Pane within a Panel by number.
newtype PaneNumber = PaneNo Natural deriving (PaneNumber -> PaneNumber -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PaneNumber -> PaneNumber -> Bool
$c/= :: PaneNumber -> PaneNumber -> Bool
== :: PaneNumber -> PaneNumber -> Bool
$c== :: PaneNumber -> PaneNumber -> Bool
Eq, Int -> PaneNumber
PaneNumber -> Int
PaneNumber -> [PaneNumber]
PaneNumber -> PaneNumber
PaneNumber -> PaneNumber -> [PaneNumber]
PaneNumber -> PaneNumber -> PaneNumber -> [PaneNumber]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: PaneNumber -> PaneNumber -> PaneNumber -> [PaneNumber]
$cenumFromThenTo :: PaneNumber -> PaneNumber -> PaneNumber -> [PaneNumber]
enumFromTo :: PaneNumber -> PaneNumber -> [PaneNumber]
$cenumFromTo :: PaneNumber -> PaneNumber -> [PaneNumber]
enumFromThen :: PaneNumber -> PaneNumber -> [PaneNumber]
$cenumFromThen :: PaneNumber -> PaneNumber -> [PaneNumber]
enumFrom :: PaneNumber -> [PaneNumber]
$cenumFrom :: PaneNumber -> [PaneNumber]
fromEnum :: PaneNumber -> Int
$cfromEnum :: PaneNumber -> Int
toEnum :: Int -> PaneNumber
$ctoEnum :: Int -> PaneNumber
pred :: PaneNumber -> PaneNumber
$cpred :: PaneNumber -> PaneNumber
succ :: PaneNumber -> PaneNumber
$csucc :: PaneNumber -> PaneNumber
Enum)


-- | This is returned from the 'handleFocusAndPanelEvents' function to indicate
-- whether a modal transition occured during the panel's (and associated Pane's)
-- handling of this event.  This can be used by the outer-level application code
-- to determine if a modal Pane was entered or exited due to the Event.
type PanelTransition = Maybe (PanelMode, PanelMode)


-- | Indicates if the specified Pane (via Type Application) is the one that was
-- modally entered as a result of processing an event (as indicated by
-- PanelTransition).
enteredModal :: forall pane n appev state panes
               . PanelOps pane n appev panes state
               => PanelTransition -> Panel n appev state panes -> Bool
               -- n.b. assumes the Panel passed here is the same panel passed to
               -- handleFocusAndPanelEvents for which the PanelTransition was
               -- obtained
enteredModal :: forall pane n appev state (panes :: [*]).
PanelOps pane n appev panes state =>
PanelTransition -> Panel n appev state panes -> Bool
enteredModal = \case
  Just (PanelMode
_, Modal PaneNumber
pnum) -> (PaneNumber
pnum forall a. Eq a => a -> a -> Bool
==) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall pane n appev (panes :: [*]) s.
PanelOps pane n appev panes s =>
Panel n appev s panes -> PaneNumber
paneNumber @pane
  PanelTransition
_ -> forall a b. a -> b -> a
const Bool
False


-- | Indicates if the specified Pane (via Type Application) is the one that was
-- modally exited (dismissed) as a result of processing an event (as indicated by
-- PanelTransition).
exitedModal :: forall pane n appev state panes
               . PanelOps pane n appev panes state
               => PanelTransition -> Panel n appev state panes -> Bool
               -- n.b. assumes the Panel passed here is the same panel passed to
               -- handleFocusAndPanelEvents for which the PanelTransition was
               -- obtained
exitedModal :: forall pane n appev state (panes :: [*]).
PanelOps pane n appev panes state =>
PanelTransition -> Panel n appev state panes -> Bool
exitedModal = \case
  Just (Modal PaneNumber
pnum, PanelMode
_) -> (PaneNumber
pnum forall a. Eq a => a -> a -> Bool
==) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall pane n appev (panes :: [*]) s.
PanelOps pane n appev panes s =>
Panel n appev s panes -> PaneNumber
paneNumber @pane
  PanelTransition
_ -> forall a b. a -> b -> a
const Bool
False


-- | When the Panel is managing focus events (e.g. when using
-- 'handleFocusAndPanelEvents'), this function can be called if there
-- has been a situation where the members of the focus ring might need
-- to be updated.  This is automatically called at the end of the
-- 'handleFocusAndPanelEvents', but it should be explicitly called
-- once when the Panel is initialized, and it can additionally be
-- called whenever needed in a situation where the
-- 'handleFocusAndPanelEvents' invocation is insufficient (e.g. a
-- separate global action enables a modal pane).
focusRingUpdate :: (Eq n, Ord n)
                => Lens' (Panel n appev s panes) (FocusRing n)
                -> Panel n appev s panes -> Panel n appev s panes
focusRingUpdate :: forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes -> Panel n appev s panes
focusRingUpdate Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
panel = let (Panel n appev s panes
p', [n]
r) = forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes -> (Panel n appev s panes, [n])
focusableNames Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
panel
                               in Panel n appev s panes
p' forall a b. a -> (a -> b) -> b
& Lens' (Panel n appev s panes) (FocusRing n)
focusL forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ forall n. Eq n => [n] -> FocusRing n -> FocusRing n
updRing [n]
r
  where
    updRing :: Eq n => [n] -> FocusRing n -> FocusRing n
    updRing :: forall n. Eq n => [n] -> FocusRing n -> FocusRing n
updRing [n]
nl FocusRing n
fcs =
      case [n]
nl of
        [] -> forall n. [n] -> FocusRing n
focusRing []
        (n
n : [n]
_) ->
          case forall n. FocusRing n -> Maybe n
focusGetCurrent FocusRing n
fcs of
            Maybe n
Nothing ->
              -- no current focus, just use new list
              forall n. Eq n => n -> FocusRing n -> FocusRing n
focusSetCurrent n
n forall a b. (a -> b) -> a -> b
$ forall n. [n] -> FocusRing n
focusRing [n]
nl
            Just n
e ->
              case forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
L.find ((n
e forall a. Eq a => a -> a -> Bool
==) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> a
head) forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [[a]]
rotations [n]
nl of
                Just [n]
r ->
                  forall n. [n] -> FocusRing n
focusRing [n]
r -- new ring with current element still focused
                Maybe [n]
Nothing ->
                  -- new focus ring doesn't include current focused
                  -- element, so just use the new list.
                  forall n. Eq n => n -> FocusRing n -> FocusRing n
focusSetCurrent n
n forall a b. (a -> b) -> a -> b
$ forall n. [n] -> FocusRing n
focusRing [n]
nl


-- | This returns the focusable Widget names for the focus ring, in the 'Ord'
-- order.  It also returns an updated panel, which internally records the input
-- focus ring if a modal is selected).  If the previous focus was a modal and the
-- new focus is not modal, this will return that previous focus ring rather than
-- the computed focus ring.
focusableNames :: (Eq n, Ord n)
               => Lens' (Panel n appev s panes) (FocusRing n)
               -> Panel n appev s panes -> (Panel n appev s panes, [n])
focusableNames :: forall n appev s (panes :: [*]).
(Eq n, Ord n) =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes -> (Panel n appev s panes, [n])
focusableNames Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
panel = forall {a} {a}.
Ord a =>
((Maybe [a], a), (Seq a, Seq a)) -> (a, [a])
finish forall a b. (a -> b) -> a -> b
$ forall n appev s (panes :: [*]) (rempanes :: [*]).
Eq n =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes
-> Panel n appev s rempanes
-> ((Maybe [n], Panel n appev s rempanes), (Seq n, Seq n))
subFocusable Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
panel Panel n appev s panes
panel
  where
    finish :: ((Maybe [a], a), (Seq a, Seq a)) -> (a, [a])
finish ((Maybe [a]
prvFcs, a
pnl), (Seq a
mdlFcs, Seq a
regFcs)) =
      let reorder :: Seq a -> [a]
reorder = forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Ord a => Seq a -> Seq a
Seq.sort
          fr :: [a]
fr = if forall (t :: * -> *) a. Foldable t => t a -> Bool
null Seq a
mdlFcs
               then forall a. a -> Maybe a -> a
fromMaybe (Seq a -> [a]
reorder Seq a
regFcs) Maybe [a]
prvFcs
               else Seq a -> [a]
reorder Seq a
mdlFcs
      in (a
pnl, [a]
fr)

subFocusable :: Eq n
             => Lens' (Panel n appev s panes) (FocusRing n)
             -> Panel n appev s panes -> Panel n appev s rempanes
             -> ((Maybe [n], Panel n appev s rempanes), (Seq n, Seq n))
subFocusable :: forall n appev s (panes :: [*]) (rempanes :: [*]).
Eq n =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes
-> Panel n appev s rempanes
-> ((Maybe [n], Panel n appev s rempanes), (Seq n, Seq n))
subFocusable Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
base = \case
  i :: Panel n appev s rempanes
i@(Panel {}) -> ((forall a. Maybe a
Nothing, Panel n appev s rempanes
i), (forall a. Monoid a => a
mempty, forall a. Monoid a => a
mempty))
  PanelWith PaneState pane appev
pd PaneFocus n
WhenFocused Panel n appev s panes
r ->
    let ((Maybe [n], Panel n appev s panes)
i', (Seq n, Seq n)
ns) = forall n appev s (panes :: [*]) (rempanes :: [*]).
Eq n =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes
-> Panel n appev s rempanes
-> ((Maybe [n], Panel n appev s rempanes), (Seq n, Seq n))
subFocusable Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
base Panel n appev s panes
r
        ns' :: (Seq n, Seq n)
ns' = let pf :: Seq n
pf = forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable Panel n appev s panes
r PaneState pane appev
pd
              in (forall a b. (a, b) -> a
fst (Seq n, Seq n)
ns, Seq n
pf forall a. Seq a -> Seq a -> Seq a
>< forall a b. (a, b) -> b
snd (Seq n, Seq n)
ns)
    in (forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
pd forall n. PaneFocus n
WhenFocused forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Maybe [n], Panel n appev s panes)
i', (Seq n, Seq n)
ns')
  PanelWith PaneState pane appev
pd PaneFocus n
WhenFocusedModal Panel n appev s panes
r ->
    let (Maybe [n]
f', Maybe (FocusRing n)
pf', Panel n appev s panes
i', (Seq n, Seq n)
ns') = forall fullpanel n appev s (panes :: [*]) rempanel
       (rempanes :: [*]) pane.
(fullpanel ~ Panel n appev s panes,
 rempanel ~ Panel n appev s rempanes,
 EventConstraints pane rempanel, Pane n appev pane, Eq n) =>
Lens' fullpanel (FocusRing n)
-> fullpanel
-> PaneState pane appev
-> Maybe (FocusRing n)
-> rempanel
-> (Maybe [n], Maybe (FocusRing n), rempanel, (Seq n, Seq n))
goModal Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
base PaneState pane appev
pd forall a. Maybe a
Nothing Panel n appev s panes
r
        pfNew :: PaneFocus n
pfNew = case Maybe (FocusRing n)
pf' of
                  Maybe (FocusRing n)
Nothing -> forall n. PaneFocus n
WhenFocusedModal
                  Just FocusRing n
x -> forall n. FocusRing n -> PaneFocus n
WhenFocusedModal' FocusRing n
x
    in ((Maybe [n]
f', forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
pd PaneFocus n
pfNew Panel n appev s panes
i'), (Seq n, Seq n)
ns')
  PanelWith PaneState pane appev
pd (WhenFocusedModal' FocusRing n
pf) Panel n appev s panes
r ->
    let (Maybe [n]
f', Maybe (FocusRing n)
pf', Panel n appev s panes
i', (Seq n, Seq n)
ns') = forall fullpanel n appev s (panes :: [*]) rempanel
       (rempanes :: [*]) pane.
(fullpanel ~ Panel n appev s panes,
 rempanel ~ Panel n appev s rempanes,
 EventConstraints pane rempanel, Pane n appev pane, Eq n) =>
Lens' fullpanel (FocusRing n)
-> fullpanel
-> PaneState pane appev
-> Maybe (FocusRing n)
-> rempanel
-> (Maybe [n], Maybe (FocusRing n), rempanel, (Seq n, Seq n))
goModal Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
base PaneState pane appev
pd (forall a. a -> Maybe a
Just FocusRing n
pf) Panel n appev s panes
r
        pfNew :: PaneFocus n
pfNew = case Maybe (FocusRing n)
pf' of
                  Maybe (FocusRing n)
Nothing -> forall n. PaneFocus n
WhenFocusedModal
                  Just FocusRing n
x -> forall n. FocusRing n -> PaneFocus n
WhenFocusedModal' FocusRing n
x
    in ((Maybe [n]
f', forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
pd PaneFocus n
pfNew Panel n appev s panes
i'), (Seq n, Seq n)
ns')
  PanelWith PaneState pane appev
pd PaneFocus n
WhenFocusedModalHandlingAllEvents Panel n appev s panes
r ->
    let (Maybe [n]
f', Maybe (FocusRing n)
pf', Panel n appev s panes
i', (Seq n, Seq n)
ns') = forall fullpanel n appev s (panes :: [*]) rempanel
       (rempanes :: [*]) pane.
(fullpanel ~ Panel n appev s panes,
 rempanel ~ Panel n appev s rempanes,
 EventConstraints pane rempanel, Pane n appev pane, Eq n) =>
Lens' fullpanel (FocusRing n)
-> fullpanel
-> PaneState pane appev
-> Maybe (FocusRing n)
-> rempanel
-> (Maybe [n], Maybe (FocusRing n), rempanel, (Seq n, Seq n))
goModal Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
base PaneState pane appev
pd forall a. Maybe a
Nothing Panel n appev s panes
r
        pfNew :: PaneFocus n
pfNew = case Maybe (FocusRing n)
pf' of
                  Maybe (FocusRing n)
Nothing -> forall n. PaneFocus n
WhenFocusedModalHandlingAllEvents
                  Just FocusRing n
x -> forall n. FocusRing n -> PaneFocus n
WhenFocusedModalHandlingAllEvents' FocusRing n
x
    in ((Maybe [n]
f', forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
pd PaneFocus n
pfNew Panel n appev s panes
i'), (Seq n, Seq n)
ns')
  PanelWith PaneState pane appev
pd (WhenFocusedModalHandlingAllEvents' FocusRing n
pf) Panel n appev s panes
r ->
    let (Maybe [n]
f', Maybe (FocusRing n)
pf', Panel n appev s panes
i', (Seq n, Seq n)
ns') = forall fullpanel n appev s (panes :: [*]) rempanel
       (rempanes :: [*]) pane.
(fullpanel ~ Panel n appev s panes,
 rempanel ~ Panel n appev s rempanes,
 EventConstraints pane rempanel, Pane n appev pane, Eq n) =>
Lens' fullpanel (FocusRing n)
-> fullpanel
-> PaneState pane appev
-> Maybe (FocusRing n)
-> rempanel
-> (Maybe [n], Maybe (FocusRing n), rempanel, (Seq n, Seq n))
goModal Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
base PaneState pane appev
pd (forall a. a -> Maybe a
Just FocusRing n
pf) Panel n appev s panes
r
        pfNew :: PaneFocus n
pfNew = case Maybe (FocusRing n)
pf' of
                  Maybe (FocusRing n)
Nothing -> forall n. PaneFocus n
WhenFocusedModalHandlingAllEvents
                  Just FocusRing n
x -> forall n. FocusRing n -> PaneFocus n
WhenFocusedModalHandlingAllEvents' FocusRing n
x
    in ((Maybe [n]
f', forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
pd PaneFocus n
pfNew Panel n appev s panes
i'), (Seq n, Seq n)
ns')
  PanelWith PaneState pane appev
x PaneFocus n
y Panel n appev s panes
r -> let ((Maybe [n], Panel n appev s panes)
i', (Seq n, Seq n)
ns) = forall n appev s (panes :: [*]) (rempanes :: [*]).
Eq n =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes
-> Panel n appev s rempanes
-> ((Maybe [n], Panel n appev s rempanes), (Seq n, Seq n))
subFocusable Lens' (Panel n appev s panes) (FocusRing n)
focusL Panel n appev s panes
base Panel n appev s panes
r
                     in (forall n appev pane state (panes :: [*]).
(Pane n appev pane,
 DrawConstraints pane (Panel n appev state panes) n,
 EventConstraints pane (Panel n appev state panes),
 DispatchEvent n appev pane (EventType pane n appev)) =>
PaneState pane appev
-> PaneFocus n
-> Panel n appev state panes
-> Panel n appev state (pane : panes)
PanelWith PaneState pane appev
x PaneFocus n
y forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Maybe [n], Panel n appev s panes)
i', (Seq n, Seq n)
ns)

goModal :: fullpanel ~ Panel n appev s panes
        => rempanel ~ Panel n appev s rempanes
        => EventConstraints pane rempanel
        => Pane n appev pane
        => Eq n
        => Lens' fullpanel (FocusRing n)
        -> fullpanel
        -> PaneState pane appev
        -> Maybe (FocusRing n)
        -> rempanel
        -> (Maybe [n], Maybe (FocusRing n), rempanel, (Seq n, Seq n))
goModal :: forall fullpanel n appev s (panes :: [*]) rempanel
       (rempanes :: [*]) pane.
(fullpanel ~ Panel n appev s panes,
 rempanel ~ Panel n appev s rempanes,
 EventConstraints pane rempanel, Pane n appev pane, Eq n) =>
Lens' fullpanel (FocusRing n)
-> fullpanel
-> PaneState pane appev
-> Maybe (FocusRing n)
-> rempanel
-> (Maybe [n], Maybe (FocusRing n), rempanel, (Seq n, Seq n))
goModal Lens' fullpanel (FocusRing n)
focusL fullpanel
base PaneState pane appev
pd Maybe (FocusRing n)
pf rempanel
r =
      let ((Maybe [n]
f, Panel n appev s rempanes
i'), (Seq n, Seq n)
ns) = forall n appev s (panes :: [*]) (rempanes :: [*]).
Eq n =>
Lens' (Panel n appev s panes) (FocusRing n)
-> Panel n appev s panes
-> Panel n appev s rempanes
-> ((Maybe [n], Panel n appev s rempanes), (Seq n, Seq n))
subFocusable Lens' fullpanel (FocusRing n)
focusL fullpanel
base rempanel
r
          fnms :: Seq n
fnms = forall n appEv pane eventcontext.
(Pane n appEv pane, EventConstraints pane eventcontext, Eq n) =>
eventcontext -> PaneState pane appEv -> Seq n
focusable rempanel
r PaneState pane appev
pd
          fpred :: Bool
fpred = Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ forall a. Seq a -> Bool
Seq.null Seq n
fnms
          ns' :: (Seq n, Seq n)
ns' =  (Seq n
fnms forall a. Seq a -> Seq a -> Seq a
>< forall a b. (a, b) -> a
fst (Seq n, Seq n)
ns, forall a b. (a, b) -> b
snd (Seq n, Seq n)
ns)
          f' :: Maybe [n]
f' = if Bool
fpred then forall a. Maybe a
Nothing else Maybe [n]
f forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (forall n. FocusRing n -> [n]
focusRingToList forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (FocusRing n)
pf)
          pf' :: Maybe (FocusRing n)
pf' = if Bool
fpred then Maybe (FocusRing n)
pf forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall a. a -> Maybe a
Just (fullpanel
baseforall s a. s -> Getting a s a -> a
^.Lens' fullpanel (FocusRing n)
focusL) else forall a. Maybe a
Nothing
      in (Maybe [n]
f', Maybe (FocusRing n)
pf', Panel n appev s rempanes
i', (Seq n, Seq n)
ns')



-- | This returns all shrl instances of the input list.
--
--  rotations [1,2,3] == [ [1,2,3], [2,3,1], [3,1,2] ]
--  rotations [1,2,3,4] == [ [1,2,3,4], [2,3,4,1], [3,4,1,2], [4,1,2,3] ]
--  rotations [1] == [ [1] ]
--  rotations [] == []
rotations :: [a] -> [ [a] ]
rotations :: forall a. [a] -> [[a]]
rotations [a]
l = forall a b. (a -> b) -> [a] -> [b]
map Int -> [a]
rotateBy forall a b. (a -> b) -> a -> b
$ [Int
0..forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
l forall a. Num a => a -> a -> a
- Int
1]
  where rotateBy :: Int -> [a]
rotateBy Int
n = forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. Semigroup a => a -> a -> a
(<>)) forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> ([a], [a])
L.splitAt Int
n [a]
l