{-# 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.

  This is done by representing each 'Pane' via a class that describes the common
  types and methods for that 'Pane', as well as the internal state of the 'Pane'.
  The full 'Pane' class is shown here in brief (more extensive documentation is
  available below):

  >  class Pane n appEv pane | pane -> n where
  >    data PaneState pane appEv
  >
  >    type InitConstraints pane initctxt :: Constraint
  >    initPaneState :: (InitConstraints pane i) => i -> PaneState pane appEv
  >
  >    type DrawConstraints pane drwctxt n :: Constraint
  >    drawPane :: (DrawConstraints pane drawcontext n, Eq n)
  >             => PaneState pane appEv -> drawcontext -> Maybe (Widget n)
  >
  >    type EventConstraints pane evctxt :: Constraint
  >    type EventType pane n appEv
  >    focusable :: (EventConstraints pane eventcontext, Eq n)
  >              => eventcontext -> PaneState pane appEv -> Seq.Seq n
  >    handlePaneEvent :: (EventConstraints pane eventcontext, Eq n)
  >                    => eventcontext
  >                    -> EventType pane n appEv
  >                    -> PaneState pane appEv
  >                    -> EventM n es (PaneState pane appEv)
  >
  >    type UpdateType pane
  >    updatePane :: UpdateType pane
  >               -> PaneState pane appEv
  >               -> PaneState pane appEv

  Each 'Pane' can be added to an overall 'Panel', where the 'Panel' provides
  appropriate focus management and consolidates event and draw dispatching to the
  (appropriate) panes.  The 'Panel' can support modal panes which grab focus (and
  are not visible wheen not active and focused), panes which participate in a
  normal focus ring, and panes which are never focused.  The 'Panel' is
  represented by a recursive data structure that is initialized by calling the
  'basePanel' function with the global application state and passing that result
  to the 'addToPanel' function for each 'Pane' that should be added to the
  'Panel'.

-}

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