{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-} -- | 'MarkupOf' is the common builder type for the (declarative) GTK+ markup -- language, supporting do syntax. 'MarkupOf' wraps many widgets, usually of -- type 'Widget', but they can be of other types. -- -- A 'Widget' value can wrap any 'Patchable' widget, hiding the underlying -- widget type, such that you can embed heterogeneous collections of widgets in -- containers. module GI.Gtk.Declarative.Markup ( Widget(..) -- * Markup , MarkupOf , Markup , single , multiple , runMarkup -- * Widget to Markup conversion , FromWidget(..) ) where import Control.Monad.Writer import Data.Typeable import GI.Gtk.Declarative.EventSource import GI.Gtk.Declarative.Patch -- | A 'Widget' value wraps a 'Patchable' and 'EventSource' widget, providing -- a constrained equivalent of a 'Dynamic' value. It is used to support -- heterogeneous containers of widgets, and to support equality -- checks on different types of widgets when calculating patches. data Widget event where Widget :: ( Typeable widget , Patchable widget , Functor widget , EventSource widget ) => widget event -> Widget event instance Functor Widget where fmap f (Widget w) = Widget (fmap f w) -- | 'Widget' is itself patchable, by delegating to the underlying -- widget instances. instance Patchable Widget where create (Widget w) = create w patch (Widget (w1 :: t1 e1)) (Widget (w2 :: t2 e2)) = case eqT @t1 @t2 of Just Refl -> patch w1 w2 _ -> Replace (create w2) instance EventSource Widget where subscribe (Widget w) = subscribe w -- * Markup -- | The declarative markup builder, primarily for using its 'Monad' instance -- and do notation to construct adjacent widgets in containers. -- -- It is parameterized with 'widget' and 'event', such that containers can -- restrict the type of their children to other types than 'Widget'. -- -- Note that the return type, 'a', is not used in this library. It's a more a -- technical necessity to have the 'Monad' instance. You can still use it if -- you need to return a value from a markup function, though. newtype MarkupOf widget event a = MarkupOf (Writer [widget event] a) deriving (Functor, Applicative, Monad) -- | Run a 'MarkupOf' builder and get its widgets. runMarkup :: MarkupOf widget event () -> [widget event] runMarkup (MarkupOf w) = execWriter w -- | Handy type alias for the common case of markup containing 'Widget's. type Markup event a = MarkupOf Widget event a -- | Construct markup from a single widget. single :: widget event -> MarkupOf widget event () single w = MarkupOf (tell [w]) -- | Construct markup from multiple widgets. multiple :: [widget event] -> MarkupOf widget event () multiple = MarkupOf . tell -- | Convert a widget to a target type. This is deliberately unconstrained in -- it's types, and is used by smart constructors to implement return type -- polymorphism, so that a smart contructor can return either a 'Widget', or -- some specifically typed 'MarkupOf', depending on the context in which it's -- used. class FromWidget widget event target | target -> event where fromWidget :: (Typeable widget, Typeable event) => widget event -> target instance FromWidget Widget event (Widget event) where fromWidget = id