{-# OPTIONS_GHC -fno-warn-unticked-promoted-constructors #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} module GI.Gtk.Declarative.Attributes.Internal.EventHandler ( Purity(..) , EventHandlerReturn(..) , EventHandler(..) , UserEventHandler , ToEventHandler(..) ) where import Data.Functor.Identity -- | A 'EventHandler' can be either pure or impure. data Purity = Pure | Impure -- | The two supported types of return values in user event handlers are encoded -- by the 'EventHandlerReturn' type; either you can return only an 'event', or if -- the underlying GTK+ callback needs to return a 'Bool', you return -- a @(Bool, event)@ tuple. data EventHandlerReturn m gtkReturn event where OnlyEvent :: m e -> EventHandlerReturn m () e ReturnAndEvent :: m (Bool, e) -> EventHandlerReturn m Bool e instance Functor m => Functor (EventHandlerReturn m gtkEventHandler) where fmap f = \case OnlyEvent e -> OnlyEvent (fmap f e) ReturnAndEvent mr -> ReturnAndEvent (fmap (fmap f) mr) -- | Encodes the user event handler in such a way that we can have -- a 'Functor' instance for arity-polymorphic event handlers. data EventHandler gtkEventHandler widget (purity :: Purity) event where PureEventHandler :: EventHandlerReturn Identity ret e -> EventHandler (IO ret) w Pure e ImpureEventHandler :: (w -> EventHandlerReturn IO ret e) -> EventHandler (IO ret) w Impure e EventHandlerFunction :: (a -> EventHandler b w p e) -> EventHandler (a -> b) w p e instance Functor (EventHandler gtkEventHandler widget purity) where fmap f = \case PureEventHandler r -> PureEventHandler (fmap f r) ImpureEventHandler r -> ImpureEventHandler (fmap (fmap f) r) EventHandlerFunction eh -> EventHandlerFunction (\a -> fmap f (eh a)) -- | Convert from a GTK+ callback type to a user event handler type (the ones -- you'd apply 'on' and 'onM' with) based on the given widget, purity, and event -- types. type family UserEventHandler gtkCallback widget (purity :: Purity) event where UserEventHandler (IO ()) widget Pure event = event UserEventHandler (IO Bool) widget Pure event = (Bool, event) UserEventHandler (IO ()) widget Impure event = widget -> IO event UserEventHandler (IO Bool) widget Impure event = widget -> IO (Bool, event) UserEventHandler (a -> b) widget purity event = a -> UserEventHandler b widget purity event -- | Internal class for converting user event handlers to encoded 'EventHandler' values. class ToEventHandler gtkEventHandler widget purity where -- | Convert from a user event handler to an 'EventHandler'. toEventHandler :: UserEventHandler gtkEventHandler widget purity event -> EventHandler gtkEventHandler widget purity event instance ToEventHandler (IO ()) widget Pure where toEventHandler = PureEventHandler . OnlyEvent . pure instance ToEventHandler (IO Bool) widget Pure where toEventHandler = PureEventHandler . ReturnAndEvent . pure instance ToEventHandler (IO ()) widget Impure where toEventHandler eh = ImpureEventHandler (OnlyEvent . eh) instance ToEventHandler (IO Bool) widget Impure where toEventHandler eh = ImpureEventHandler (ReturnAndEvent . eh) instance (ToEventHandler b widget purity) => ToEventHandler (a -> b) widget purity where toEventHandler f = EventHandlerFunction (toEventHandler . f)