{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module GI.Gtk.Declarative.CustomWidget
( CustomPatch(..)
, CustomWidget(..)
)
where
import Data.Typeable
import Data.Vector (Vector)
import qualified GI.Gtk as Gtk
import GI.Gtk.Declarative.Attributes
import GI.Gtk.Declarative.Attributes.Collected
import GI.Gtk.Declarative.EventSource
import GI.Gtk.Declarative.Patch
import GI.Gtk.Declarative.State
data CustomPatch widget internalState
= CustomReplace
| CustomModify (widget -> IO internalState)
| CustomKeep
data CustomWidget widget params internalState event =
CustomWidget
{ customWidget :: Gtk.ManagedPtr widget -> widget
, customCreate :: params -> IO (widget, internalState)
, customPatch :: params -> params -> internalState -> CustomPatch widget internalState
, customSubscribe :: params -> internalState -> widget -> (event -> IO ()) -> IO Subscription
, customAttributes :: Vector (Attribute widget event)
, customParams :: params
} deriving (Functor)
instance ( Typeable widget
, Typeable internalState
, Gtk.IsWidget widget
)
=> Patchable (CustomWidget widget params internalState) where
create custom = do
(widget, internalState) <- customCreate custom (customParams custom)
Gtk.widgetShow widget
let collected = collectAttributes (customAttributes custom)
updateProperties widget mempty (collectedProperties collected)
sc <- Gtk.widgetGetStyleContext widget
updateClasses sc mempty (collectedClasses collected)
pure (SomeState (StateTreeWidget (StateTreeNode widget sc collected internalState)))
patch (SomeState (stateTree :: StateTree st w e c cs)) old new =
case (eqT @cs @internalState, eqT @widget @w) of
(Just Refl, Just Refl) ->
case customPatch
new
(customParams old)
(customParams new)
(stateTreeCustomState (stateTreeNode stateTree))
of
CustomReplace -> Replace (create new)
CustomModify f -> Modify $ do
let widget' = stateTreeNodeWidget stateTree
let oldCollected = stateTreeCollectedAttributes (stateTreeNode stateTree)
newCollected = collectAttributes (customAttributes new)
updateProperties widget' (collectedProperties oldCollected) (collectedProperties newCollected)
updateClasses (stateTreeStyleContext (stateTreeNode stateTree)) (collectedClasses oldCollected) (collectedClasses newCollected)
internalState' <-
f =<< Gtk.unsafeCastTo (customWidget new) widget'
let node = stateTreeNode stateTree
return (SomeState (StateTreeWidget node { stateTreeCustomState = internalState'
, stateTreeCollectedAttributes = newCollected
}))
CustomKeep -> Keep
_ -> Replace (create new)
instance (Typeable internalState, Gtk.GObject widget)
=> EventSource (CustomWidget widget params internalState) where
subscribe custom (SomeState (stateTree :: StateTree st w e c cs)) cb =
case eqT @cs @internalState of
Just Refl -> do
w' <- Gtk.unsafeCastTo (customWidget custom) (stateTreeNodeWidget stateTree)
customSubscribe custom (customParams custom) (stateTreeCustomState (stateTreeNode stateTree)) w' cb
Nothing -> pure (fromCancellation (pure ()))