This blog post is used to track my progress in porting gi-gtk-declarative to Gtk4.
TODO Understand how gi-gtk-declarative works
TODO The overall architecture
Terminology
The difference between “Widget” and “widget”
EventSource
class EventSource widget where
subscribe :: widget event -- ^ Declarative widget with event handlers.
-> SomeState -- ^ State of rendered widget tree.
-> (event -> IO ()) -- ^ Event callback, invoked on each emitted event until
-- the 'Subscription' is cancelled, or widget is otherwise
-- destroyed.
-> IO Subscription -- ^ A 'Subscription' is returned, which can be cancelled.
The Widget wrapper and FromWidget class
data Widget event where
Widget
::( Typeable widget
Patchable widget -- ^ widget is Patchable
, Functor widget
, EventSource widget -- ^ widget is EventSource
,
)=> widget event
-> Widget event
Functor is defined for Widget
The default Patchable implementation delegates creation and patching to the underlying widget. The default EventSource implmentation delegates subscription to the underlying widget.
class FromWidget widget target where
fromWidget :: widget event -> target event
instance ( Typeable parent
Typeable child
, Patchable (parent child)
, Functor (parent child)
, EventSource (parent child)
,
)=> FromWidget (parent child) Widget where
= Widget fromWidget
FromWidget a b means that you can convert from (a event) to (b event). You can convert from unwrapped widget to wrapped widget or vice versa. The instance defined here provides the default implementation to wrap a widget.
TODO What is this (parent child) thing???
Firstly, remember that Typeable is polykinded.
Notice that (parent child) has kind
* -> *
, we can guess it’s like (parent child) ~ widgetThe purpose of using
(parent child)
instead ofwidget
is that we preserve the knowledge that both parent and child is Typeable?
TODO Single Widget
use widget smart constructor from SingleWidget.hs
data SingleWidget widget event where
SingleWidget
::(Typeable widget, Gtk.IsWidget widget, Functor (Attribute widget))
=> (Gtk.ManagedPtr widget -> widget)
-> Vector (Attribute widget event)
-> SingleWidget widget event
-- | Construct a /leaf/ widget, i.e. one without any children.
widget :: ( Typeable widget
Gtk.IsWidget widget
, FromWidget (SingleWidget widget) target
,
)=> (Gtk.ManagedPtr widget -> widget) -- ^ A widget constructor from the underlying gi-gtk library.
-> Vector (Attribute widget event) -- ^ List of 'Attribute's.
-> target event -- ^ The target, whose type is decided by 'FromWidget'.
= fromWidget . SingleWidget ctor widget ctor
The patchable instance
Attribute is from GI.GTK.Attributes
TODO understand the shadow state tree
Patchable can be diffed to produce a patch a patch is IO SomeState
-- | 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
TODO deal with the removal of IsBin and IsContainer class
removal of destroyWidget
removal of ChildStates
Paned
Gtk3: https://docs.gtk.org/gtk3/class.Paned.html Gtk4: https://docs.gtk.org/gtk4/class.Paned.html
call label function in instances
in Data.GI.Base
get :: forall info attr obj result m. (AttrGetC info obj attr result, MonadIO m) => obj -> AttrLabelProxy (attr :: Symbol) -> m result
also a possible example from Attributes.hs
-- | The attribute GADT represent a supported attribute for a declarative
-- widget. This extends the regular notion of GTK+ attributes to also include
-- event handling and CSS classes.
data Attribute widget event where
-- | An attribute/value mapping for a declarative widget. The
-- 'GI.AttrLabelProxy' is parameterized by 'attr', which represents the
-- GTK-defined attribute name. The underlying GI object needs to support
-- the /construct/, /get/, and /set/ operations for the given attribute.
:=)
( ::(GI.AttrOpAllowed 'GI.AttrConstruct info widget
GI.AttrOpAllowed 'GI.AttrSet info widget
, GI.AttrGetC info widget attr getValue
, GI.AttrSetTypeConstraint info setValue
, KnownSymbol attr
, Typeable attr
, Eq setValue
, Typeable setValue
,
)=> GI.AttrLabelProxy (attr :: Symbol) -> setValue -> Attribute widget event
AttrSetC -> AttrSetTypeConstraint -> IsWidget
so we need IsWidget in the context of Bin child
seems that GHC cannot infer it? is it because of Widget and fromWidget?