content: {-# LANGUAGE DataKinds      #-}
  {-# LANGUAGE GADTs          #-}
  {-# LANGUAGE KindSignatures #-}
  {-# LANGUAGE RankNTypes     #-}
  -- | The 'StateTree' and 'SomeState' form a "shadow state"
  -- representation, used in patching. Declarative widgets can return,
  -- and later on reuse, its underlying GTK+ widget, collected
  -- properties and classes, style context, custom internal state, and
  -- child states. This reduces the need for querying GTK+ widgets
  -- excessively, and recalculating/resetting, greatly improving the
  -- performance of patching.
  module GI.Gtk.Declarative.State where
  
  import           Data.Typeable
  
  import           Data.Vector                             (Vector)
  import qualified GI.Gtk                                  as Gtk
  
  import           GI.Gtk.Declarative.Attributes.Collected
  import           GI.Gtk.Declarative.Container.Class
  
  -- | A 'Data.Dynamic.Dynamic'-like container of a 'StateTree' value.
  data SomeState where
    SomeState
      :: ( Gtk.IsWidget widget
        , Typeable widget
        , Typeable customState
        )
      => StateTree stateType widget child event customState
      -> SomeState
  
  -- | The types of state trees that are available, matching the types
  -- of GTK+ widgets (single widget, bin, and container.)
  data StateType = WidgetState | BinState | ContainerState
  
  -- | A state tree for a specific 'widget'. This is built up recursively
  -- to contain child state trees, for bin and container child widgets.
  data StateTree (stateType :: StateType) widget child event customState where
    StateTreeWidget
      :: !(StateTreeNode widget event customState)
      -> StateTree 'WidgetState widget child event customState
    StateTreeBin
      :: !(StateTreeNode widget event customState)
      -> SomeState
      -> StateTree 'BinState widget child event customState
    StateTreeContainer
      :: ( Gtk.IsContainer widget
         , IsContainer widget child
         )
      => !(StateTreeNode widget event customState)
      -> Vector SomeState
      -> StateTree 'ContainerState widget child event customState
  
  -- | The common structure for all state tree nodes.
  data StateTreeNode widget event customState = StateTreeNode
    { stateTreeWidget              :: !widget
    , stateTreeStyleContext        :: !Gtk.StyleContext
    , stateTreeCollectedAttributes :: !(Collected widget event)
    , stateTreeCustomState         :: customState
    }
  
  -- * Convenience accessor functions
  
  -- | Get the common state tree node information.
  stateTreeNode
    :: StateTree stateType widget child event customState
    -> StateTreeNode widget event customState
  stateTreeNode (StateTreeWidget s     ) = s
  stateTreeNode (StateTreeBin       s _) = s
  stateTreeNode (StateTreeContainer s _) = s
  
  -- | Get the specific type of GTK+ widget of a state tree.
  stateTreeNodeWidget :: StateTree stateType widget child event customState -> widget
  stateTreeNodeWidget = stateTreeWidget . stateTreeNode
  
  -- | Get the GTK+ widget, cast to 'Gtk.Widget', of /some/ state tree.
  someStateWidget :: SomeState -> IO Gtk.Widget
  someStateWidget (SomeState st) = Gtk.toWidget (stateTreeNodeWidget st)
  