content: {-|
  Module      : Monomer.Core.WidgetTypes
  Copyright   : (c) 2018 Francisco Vallarino
  License     : BSD-3-Clause (see the LICENSE file)
  Maintainer  : fjvallarino@gmail.com
  Stability   : experimental
  Portability : non-portable
  
  Basic types and definitions for Widgets.
  -}
  {-# LANGUAGE ConstraintKinds #-}
  {-# LANGUAGE DeriveGeneric #-}
  {-# LANGUAGE DerivingStrategies #-}
  {-# LANGUAGE ExistentialQuantification #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE RankNTypes #-}
  {-# LANGUAGE Strict #-}
  
  module Monomer.Core.WidgetTypes where
  
  import Control.Concurrent (MVar)
  import Control.Lens (ALens')
  import Data.Default
  import Data.Map.Strict (Map)
  import Data.Sequence (Seq)
  import Data.String (IsString(..))
  import Data.Text (Text)
  import Data.Typeable (Typeable, typeOf)
  import Data.Word (Word64)
  import GHC.Generics
  import TextShow
  
  import qualified Data.Text as T
  
  import Monomer.Common
  import Monomer.Core.StyleTypes
  import Monomer.Core.ThemeTypes
  import Monomer.Event.Types
  import Monomer.Graphics.Types
  
  {-|
  Time expressed in milliseconds. Useful for representing the time of events,
  length of intervals, start time of the application and elapsed time since its
  start.
  
  It can be converted from/to other numeric types using the standard functions.
  -}
  newtype Millisecond = Millisecond {
    unMilliseconds :: Word64
  } deriving newtype (Eq, Ord, Enum, Bounded, Num, Real, Integral, Read, Show, Default, TextShow)
    deriving (Generic)
  
  -- | Type constraints for a valid model
  type WidgetModel s = Typeable s
  -- | Type constraints for a valid event
  type WidgetEvent e = Typeable e
  
  {-|
  Map of WidgetKeys to WidgetNodes. This association is valid only in the context
  of a Composite, with visibility of keys restricted to its scope. WidgetKeys
  inside nested Composites are /not/ visible.
  -}
  type WidgetKeyMap s e = Map WidgetKey (WidgetNode s e)
  
  -- | Direction of focus movement.
  data FocusDirection
    = FocusFwd  -- ^ Focus moving forward (usually left to right, top to bottom).
    | FocusBwd  -- ^ Focus moving backward (usually right to left, top to bottom).
    deriving (Eq, Show)
  
  -- | 'WidgetRequest' specific for window related operations.
  data WindowRequest
    = WindowSetTitle Text  -- ^ Sets the title of the window to the given text.
    | WindowSetFullScreen  -- ^ Switches to fullscreen mode.
    | WindowMaximize       -- ^ Maximizes the window.
    | WindowMinimize       -- ^ Minimizes the window.
    | WindowRestore        -- ^ Restores the window to its previous normal size.
    | WindowBringToFront   -- ^ Brings the window to the foreground.
    deriving (Eq, Show)
  
  -- | Type of a widget. Used during the merge process.
  newtype WidgetType
    = WidgetType Text
    deriving (Eq, Show, Generic)
  
  instance IsString WidgetType where
    fromString = WidgetType . T.pack
  
  {-|
  Widgets can receive/report data using lenses or direct values. Reporting
  WidgetValue requires user events (in general, an onChange event).
  -}
  data WidgetData s a
    = WidgetValue a            -- ^ A direct value.
    | WidgetLens (ALens' s a)  -- ^ A lens into the parent model.
  
  {-|
  Widgets instances have an associated path from the root, which is unique at a
  specific point in time. This path may change, since widgets could be added
  before or after it (for example, a widget is added to the beginning of a list).
  WidgetIds are used by the runtime to create an association from a unique
  identifier to the current valid path of an instance; this unique identifier, the
  WidgetId, is the result of combining the timestamp when the instance was created
  and its path at that time.
  
  Several WidgetRequests rely on this to find the destination of asynchronous
  requests (tasks, clipboard, etc).
  -}
  data WidgetId = WidgetId {
    _widTs :: Millisecond,  -- ^ The timestamp when the instance was created.
    _widPath :: Path      -- ^ The path at creation time.
  } deriving (Eq, Show, Ord, Generic)
  
  instance Default WidgetId where
    def = WidgetId 0 emptyPath
  
  {-|
  During the merge process, widgets are matched based on WidgetType and WidgetKey.
  By default an instance's key is null, which means any matching type will be
  valid for merging. If you have items that can be reordered, using a key makes
  sure merge picks the correct instance for merging. Keys should be unique within
  the context of a Composite. Duplicate key behavior is undefined.
  -}
  newtype WidgetKey
    = WidgetKey Text
    deriving (Eq, Show, Ord, Generic)
  
  instance IsString WidgetKey where
    fromString = WidgetKey . T.pack
  
  {-|
  Wrapper of a Typeable instance representing the state of a widget. The widget is
  in charge of casting to the correct type.
  -}
  data WidgetState
    = forall i . WidgetModel i => WidgetState i
  
  instance Show WidgetState where
    show (WidgetState state) = "WidgetState: " ++ show (typeOf state)
  
  {-|
  Wrapper of a Typeable instance representing shared data between widgets. Used,
  for example, by image widget to avoid loading the same image multiple times. The
  widget is in charge of casting to the correct type.
  -}
  data WidgetShared
    = forall i . Typeable i => WidgetShared i
  
  instance Show WidgetShared where
    show (WidgetShared shared) = "WidgetShared: " ++ show (typeOf shared)
  
  {-|
  WidgetRequests are the way a widget can perform side effects, such as changing
  cursor icons, get/set the clipboard and perform asynchronous tasks. These
  requests are included as part of a 'WidgetResult' in different points in the
  lifecycle of a widget.
  -}
  data WidgetRequest s e
    -- | Ignore events generated by the parent. Could be used to consume the tab
    --   key and avoid having the focus move to the next widget.
    = IgnoreParentEvents
    -- | Ignore children events. Scroll relies on this to handle click/wheel.
    | IgnoreChildrenEvents
    -- | The widget content changed and requires a different size. Processed at
    --   the end of the cycle, since several widgets may request it.
    | ResizeWidgets WidgetId
    -- | The widget content changed and requires a different size. Processed
    --   immediately. Avoid if possible, since it can affect performance.
    | ResizeWidgetsImmediate WidgetId
    -- | Moves the focus, optionally indicating a starting widgetId.
    | MoveFocus (Maybe WidgetId) FocusDirection
    -- | Sets the focus to the given widgetId.
    | SetFocus WidgetId
    -- | Requests the clipboard contents. It will be received as a SystemEvent.
    | GetClipboard WidgetId
    -- | Sets the clipboard to the given 'ClipboardData'.
    | SetClipboard ClipboardData
    -- | Sets the viewport that should be remain visible when an on-screen
    --   keyboard is displayed. Required for mobile.
    | StartTextInput Rect
    -- | Resets the keyboard viewport,
    | StopTextInput
    -- | Sets a widget as the base target of future events. This is used by the
    --   dropdown component to handle list events; this list, acting as an
    --   overlay, is displayed on top of all other widgets. Popup uses it too.
    | SetOverlay WidgetId Path
    -- | Removes the existing overlay.
    | ResetOverlay WidgetId
    -- | Sets the current active cursor icon. This acts as a stack, and resetting
    --   a widgetId means going back to the cursor set immediately before.
    | SetCursorIcon WidgetId CursorIcon
    -- | Removes a cursor icon from the stack. Duplicate requests are ignored.
    | ResetCursorIcon WidgetId
    -- | Sets the current item being dragged and the message it carries. This
    --   message can be used by targets to check if they accept it or not.
    | StartDrag WidgetId Path WidgetDragMsg
    -- | Cancels the current dragging process.
    | StopDrag WidgetId
    -- | Requests rendering a single frame. Rendering is not done at a fixed rate,
    --   in order to reduce CPU usage. Widgets are responsible for requesting
    --   rendering at points of interest. Mouse (except mouse move) and keyboard
    --   events automatically generate render requests, but the result of a
    --   'RunTask' or 'RunProducer' does not.
    | RenderOnce
    -- | Useful if a widget requires periodic rendering. An optional maximum
    --   number of frames can be provided.
    | RenderEvery WidgetId Millisecond (Maybe Int)
    -- | Stops a previous periodic rendering request.
    | RenderStop WidgetId
    {-|
    Requests an image to be removed from the Renderer. In general, used by the
    dispose function.
    -}
    | RemoveRendererImage Text
    -- | Requests to exit the application. Can also be used to cancel a previous
    --   request (or a window close).
    | ExitApplication Bool
    -- | Performs a 'WindowRequest'.
    | UpdateWindow WindowRequest
    {-|
    Request a model update. This usually involves lenses and
    'Monomer.Widgets.Util.Widget.widgetDataSet'.
    -}
    | UpdateModel (s -> s)
    -- | Updates the path of a given widget. Both "Monomer.Widgets.Single" and
    --   "Monomer.Widgets.Container" handle this automatically.
    | SetWidgetPath WidgetId Path
    -- | Clears an association between widgetId and path.
    | ResetWidgetPath WidgetId
    -- | Raises a user event, which usually will be processed in handleEvent by a
    --   "Monomer.Widgets.Composite" instance.
    | WidgetEvent e => RaiseEvent e
    -- | Sends a message to the given widgetId. If the target does not expect the
    --   message's type, it will be ignored.
    | forall i . Typeable i => SendMessage WidgetId i
    -- | Runs an asynchronous tasks. It is mandatory to return a message that will
    --   be sent to the task owner (this is the only way to feed data back).
    | forall i . Typeable i => RunTask WidgetId Path (IO i)
    -- | Similar to RunTask, but can generate unlimited messages. This is useful
    --   for WebSockets and similar data sources. It receives a function that
    --   can be used to send messages back to the producer owner.
    | forall i . Typeable i => RunProducer WidgetId Path ((i -> IO ()) -> IO ())
    -- | Runs an asynchronous tasks in the render thread. It is mandatory to
    --   return a message that will be sent to the task owner (this is the only
    --   way to feed data back). This should only be used when implementing low
    --   level rendering widgets that need to create API specific resources.
    | forall i . Typeable i => RunInRenderThread WidgetId Path (IO i)
  
  instance Eq e => Eq (WidgetRequest s e) where
    IgnoreParentEvents == IgnoreParentEvents = True
    IgnoreChildrenEvents == IgnoreChildrenEvents = True
    ResizeWidgets w1 == ResizeWidgets w2 = w1 == w2
    ResizeWidgetsImmediate w1 == ResizeWidgetsImmediate w2 = w1 == w2
    MoveFocus w1 fd1 == MoveFocus w2 fd2 = (w1, fd1) == (w2, fd2)
    SetFocus w1 == SetFocus w2 = w1 == w2
    GetClipboard w1 == GetClipboard w2 = w1 == w2
    SetClipboard c1 == SetClipboard c2 = c1 == c2
    StartTextInput r1 == StartTextInput r2 = r1 == r2
    StopTextInput == StopTextInput = True
    SetOverlay w1 p1 == SetOverlay w2 p2 = (w1, p1) == (w2, p2)
    ResetOverlay w1 == ResetOverlay w2 = w1 == w2
    SetCursorIcon w1 c1 == SetCursorIcon w2 c2 = (w1, c1) == (w2, c2)
    ResetCursorIcon w1 == ResetCursorIcon w2 = w1 == w2
    StartDrag w1 p1 m1 == StartDrag w2 p2 m2 = (w1, p1, m1) == (w2, p2, m2)
    StopDrag w1 == StopDrag w2 = w1 == w2
    RenderOnce == RenderOnce = True
    RenderEvery p1 c1 r1 == RenderEvery p2 c2 r2 = (p1, c1, r1) == (p2, c2, r2)
    RenderStop p1 == RenderStop p2 = p1 == p2
    ExitApplication e1 == ExitApplication e2 = e1 == e2
    UpdateWindow w1 == UpdateWindow w2 = w1 == w2
    SetWidgetPath w1 p1 == SetWidgetPath w2 p2 = (w1, p1) == (w2, p2)
    ResetWidgetPath w1 == ResetWidgetPath w2 = w1 == w2
    RaiseEvent e1 == RaiseEvent e2 = e1 == e2
    _ == _ = False
  
  {-|
  Result of widget operations (init, merge, handleEvent, etc). The node is
  mandatory. The 'Monomer.Widgets.Util.Widget.resultNode',
  'Monomer.Widgets.Util.Widget.resultEvts',
  'Monomer.Widgets.Util.Widget.resultReqs' and
  'Monomer.Widgets.Util.Widget.resultReqsEvts' helper functions can also be used.
  
  In general a result starts in a child widget, but parent widgets can append
  requests or new versions of themselves.
  -}
  data WidgetResult s e = WidgetResult {
    _wrNode :: WidgetNode s e,              -- ^ The updated widget node.
    _wrRequests :: Seq (WidgetRequest s e)  -- ^ The widget requests.
  }
  
  -- This instance is lawless (there is not an empty widget): use with caution
  instance Semigroup (WidgetResult s e) where
    er1 <> er2 = WidgetResult {
      _wrNode = _wrNode er2,
      _wrRequests = _wrRequests er1 <> _wrRequests er2
    }
  
  -- | Used to indicate active layout direction. Some widgets, such as spacer,
  --   can use it to adapt themselves.
  data LayoutDirection
    = LayoutNone
    | LayoutHorizontal
    | LayoutVertical
    deriving (Eq, Show, Generic)
  
  -- | The widget environment. This includes system information, active viewport,
  --   and input status among other things.
  data WidgetEnv s e = WidgetEnv {
    -- | The OS of the host.
    _weOs :: Text,
    -- | Device pixel rate.
    _weDpr :: Double,
    -- | Indicates whether the application is running on ghci.
    _weIsGhci :: Bool,
    -- | The timestamp in milliseconds when the application started.
    _weAppStartTs :: Millisecond,
    -- | Provides helper functions for calculating text size.
    _weFontManager :: FontManager,
    -- | Returns the node info, and its parents', given a path from root.
    _weFindBranchByPath :: Path -> Seq WidgetNodeInfo,
    -- | The mouse button that is considered main.
    _weMainButton :: Button,
    -- | The mouse button that is considered as secondary or context button.
    _weContextButton :: Button,
    -- | The active theme. Some widgets derive their base style from this.
    _weTheme :: Theme,
    -- | The main window size.
    _weWindowSize :: Size,
    -- | The active map of shared data.
    _weWidgetShared :: MVar (Map Text WidgetShared),
    {-|
    The active map of WidgetKey -> WidgetNode, if any. This map is restricted to
    to the parent "Monomer.Widgets.Composite".
  
    It is recommended to not use this map directly, since `WidgetNodeInfo` may be
    stale (path and widgetId are always valid). Because of this it is safer to use
    the 'Monomer.Core.Util.widgetIdFromKey', 'Monomer.Core.Util.nodeInfoFromKey'
    and 'Monomer.Core.Util.nodeInfoFromPath' utility functions.
    -}
    _weWidgetKeyMap :: WidgetKeyMap s e,
    -- | The currently hovered path, if any.
    _weHoveredPath :: Maybe Path,
    -- | The currently focused path. There's always one, even if it's empty.
    _weFocusedPath :: Path,
    -- | The current overlay path, if any.
    _weOverlayPath :: Maybe Path,
    -- | The current drag message and source path, if any is active.
    _weDragStatus :: Maybe (Path, WidgetDragMsg),
    -- | Indicates the path and position where the main button was pressed.
    _weMainBtnPress :: Maybe (Path, Point),
    -- | The current active cursor, and the path that set it.
    _weCursor :: Maybe (Path, CursorIcon),
    -- | The current user model.
    _weModel :: s,
    -- | The input status, mainly mouse and keyboard.
    _weInputStatus :: InputStatus,
    {-|
    The timestamp in milliseconds when this event/message cycle started. This
    value starts from zero each time the application is run.
    -}
    _weTimestamp :: Millisecond,
    {-|
    Whether the theme changed in this cycle. Should be considered when a widget
    avoids merging as optimization, as the styles may have changed.
    -}
    _weThemeChanged :: Bool,
    -- | Indicates whether the current widget is in a top layer (zstack).
    _weInTopLayer :: Point -> Bool,
    -- | The current layout direction.
    _weLayoutDirection :: LayoutDirection,
    {-|
    The active viewport.  This may be smaller than the widget's viewport, if it's
    currently inside a scroll or similar.
    -}
    _weViewport :: Rect,
    -- | The current accumulated offset. This can be affected by scroll.
    _weOffset :: Point
  }
  
  -- | Complementary information to a Widget, forming a node in the widget tree.
  data WidgetNodeInfo =
    WidgetNodeInfo {
      -- | Type of the widget.
      _wniWidgetType :: WidgetType,
      -- | The identifier at creation time of the widget (runtime generated).
      _wniWidgetId :: WidgetId,
      -- | Key/Identifier of the widget (user provided). Used for merging.
      _wniKey :: Maybe WidgetKey,
      -- | The path of the instance in the widget tree, as a set of indexes.
      _wniPath :: Path,
      -- | The requested width for the widget. The one in style takes precedence.
      _wniSizeReqW :: SizeReq,
      -- | The requested height for the widget. The one in style takes precedence.
      _wniSizeReqH :: SizeReq,
      -- | Indicates if the widget is enabled for user interaction.
      _wniEnabled :: Bool,
      -- | Indicates if the widget is visible.
      _wniVisible :: Bool,
      -- | Indicates whether the widget can receive focus.
      _wniFocusable :: Bool,
      {-|
      The area of the window where the widget can draw. Could be out of bounds or
      partially invisible if inside a scroll. The viewport on 'WidgetEnv' defines
      what is currently visible.
      -}
      _wniViewport :: Rect,
      -- | Style attributes of the widget instance.
      _wniStyle :: Style
    } deriving (Eq, Show, Generic)
  
  instance Default WidgetNodeInfo where
    def = WidgetNodeInfo {
      _wniWidgetType = WidgetType (T.pack ""),
      _wniWidgetId = def,
      _wniKey = Nothing,
      _wniPath = emptyPath,
      _wniSizeReqW = def,
      _wniSizeReqH = def,
      _wniEnabled = True,
      _wniVisible = True,
      _wniFocusable = False,
      _wniViewport = def,
      _wniStyle = def
    }
  
  -- | An instance of the widget in the widget tree.
  data WidgetNode s e = WidgetNode {
    -- | The actual widget.
    _wnWidget :: Widget s e,
    -- | Information about the instance.
    _wnInfo :: WidgetNodeInfo,
    -- | The children widgets, if any.
    _wnChildren :: Seq (WidgetNode s e)
  }
  
  {-|
  An instance of the widget in the widget tree, without specific type information.
  This allows querying for widgets that may be nested in Composites, which are not
  visible as a regular 'WidgetNode' because of possible type mismatches (see
  'WidgetKeyMap').
  -}
  data WidgetInstanceNode = WidgetInstanceNode {
    -- | Information about the instance.
    _winInfo :: WidgetNodeInfo,
    -- | The widget state, if any.
    _winState :: Maybe WidgetState,
    -- | The children widget, if any.
    _winChildren :: Seq WidgetInstanceNode
  } deriving (Show, Generic)
  
  {-|
  Main widget type. This is the type all widgets implement. In general it's not
  needed to implement this type directly, and it's easier to use
  "Monomer.Widgets.Container" for widgets with children elements and
  "Monomer.Widgets.Single" for widgets without children.
  -}
  data Widget s e =
    Widget {
      {-|
      Initializes the given node. This could include rebuilding the widget in
      case internal state needs to use model/environment information, generate
      user events or make requests to the runtime.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
  
      Returns:
  
      - The result of the init operation.
      -}
      widgetInit
        :: WidgetEnv s e
        -> WidgetNode s e
        -> WidgetResult s e,
      {-|
      Merges the current node with the node it matched with during the merge
      process. Receives the newly created node (whose *init* function is not
      called), the previous node and the state extracted from that node. This
      process is widget dependent, and may use or ignore the previous state
      depending on newly available information.
  
      In general, you want to at least keep the previous state unless the widget
      is stateless or only consumes model/environment information.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
      - The previous widget node.
  
      Returns:
  
      - The result of the merge operation.
      -}
      widgetMerge
        :: WidgetEnv s e
        -> WidgetNode s e
        -> WidgetNode s e
        -> WidgetResult s e,
      {-|
      Disposes the current node. Only used by widgets which allocate resources
      during /init/ or /merge/, and will usually involve requests to the runtime.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
  
      Returns:
  
      - The result of the dispose operation.
      -}
      widgetDispose
        :: WidgetEnv s e
        -> WidgetNode s e
        -> WidgetResult s e,
      {-|
      Returns the current internal state, which can later be used when during the
      merge process.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
  
      Returns:
  
      - The internal state, if any.
      -}
      widgetGetState
        :: WidgetEnv s e
        -> WidgetNode s e
        -> Maybe WidgetState,
      {-|
      Returns information about the instance and its children.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
  
      Returns:
  
      - The untyped node information.
      -}
      widgetGetInstanceTree
        :: WidgetEnv s e
        -> WidgetNode s e
        -> WidgetInstanceNode,
      {-|
      Returns the next focusable node. What next/previous is, depends on how the
      widget works. Moving left to right, top to bottom is usually considered
      forward.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
      - The direction in which focus is moving.
      - The path to start the search from.
  
      Returns:
  
      - The next focusable node info.
      -}
      widgetFindNextFocus
        :: WidgetEnv s e
        -> WidgetNode s e
        -> FocusDirection
        -> Path
        -> Maybe WidgetNodeInfo,
      {-|
      Returns the currently hovered widget, if any.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
      - The path to start the search from.
      - The point to test for.
  
      Returns:
  
      - The hovered child index, if any.
      -}
      widgetFindByPoint
        :: WidgetEnv s e
        -> WidgetNode s e
        -> Path
        -> Point
        -> Maybe WidgetNodeInfo,
      {-|
      Returns the widget matching the given path, plus all its parents.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
      - The path to search for.
  
      Returns:
  
      - The sequence of widgets up to path, ordered from root to target.
      -}
      widgetFindBranchByPath
        :: WidgetEnv s e
        -> WidgetNode s e
        -> Path
        -> Seq WidgetNodeInfo,
      {-|
      Receives a System event and, optionally, returns a result. This can include
      an updated version of the widget (in case it has internal state), user
      events or requests to the runtime.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
      - The target path of the event.
      - The SystemEvent to handle.
  
      Returns:
  
      - The result of handling the event, if any.
      -}
      widgetHandleEvent
        :: WidgetEnv s e
        -> WidgetNode s e
        -> Path
        -> SystemEvent
        -> Maybe (WidgetResult s e),
      {-|
      Receives a message and, optionally, returns a result. This can include an
      updated version of the widget (in case it has internal state), user events
      or requests to the runtime. There is no validation regarding the message
      type, and the widget should take care of /casting/ to the correct type using
      'Data.Typeable.cast'.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
      - The target path of the message.
      - The message to handle.
  
      Returns:
  
      - The result of handling the message, if any.
      -}
      widgetHandleMessage
        :: forall i . Typeable i
        => WidgetEnv s e
        -> WidgetNode s e
        -> Path
        -> i
        -> Maybe (WidgetResult s e),
      {-|
      Returns the preferred size for the widget.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
  
      Returns:
  
      - The horizontal and vertical requirements.
      -}
      widgetGetSizeReq
        :: WidgetEnv s e
        -> WidgetNode s e
        -> (SizeReq, SizeReq),
      {-|
      Resizes the widget to the provided size.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
      - The new viewport.
      - Helper to checks if a given path, or its children, requested resize.
  
      Returns:
  
      - The result of resizing the widget.
      -}
      widgetResize
        :: WidgetEnv s e
        -> WidgetNode s e
        -> Rect
        -> (Path -> Bool)
        -> WidgetResult s e,
      {-|
      Renders the widget's content using the given Renderer.
  
      Arguments:
  
      - The widget environment.
      - The widget node.
      - The renderer, providing low level drawing functions.
  
      Returns:
  
      - The IO action with rendering instructions.
      -}
      widgetRender
        :: WidgetEnv s e
        -> WidgetNode s e
        -> Renderer
        -> IO ()
    }
  
  instance Show (WidgetRequest s e) where
    show IgnoreParentEvents = "IgnoreParentEvents"
    show IgnoreChildrenEvents = "IgnoreChildrenEvents"
    show (ResizeWidgets wid) = "ResizeWidgets: " ++ show wid
    show (ResizeWidgetsImmediate wid) = "ResizeWidgetsImmediate: " ++ show wid
    show (MoveFocus start dir) = "MoveFocus: " ++ show (start, dir)
    show (SetFocus path) = "SetFocus: " ++ show path
    show (GetClipboard wid) = "GetClipboard: " ++ show wid
    show (SetClipboard _) = "SetClipboard"
    show (StartTextInput rect) = "StartTextInput: " ++ show rect
    show StopTextInput = "StopTextInput"
    show (SetOverlay wid path) = "SetOverlay: " ++ show (wid, path)
    show (ResetOverlay wid) = "ResetOverlay: " ++ show wid
    show (SetCursorIcon wid icon) = "SetCursorIcon: " ++ show (wid, icon)
    show (ResetCursorIcon wid) = "ResetCursorIcon: " ++ show wid
    show (StartDrag wid path info) = "StartDrag: " ++ show (wid, path, info)
    show (StopDrag wid) = "StopDrag: " ++ show wid
    show RenderOnce = "RenderOnce"
    show (RenderEvery wid ms repeat) = "RenderEvery: " ++ show (wid, ms, repeat)
    show (RenderStop wid) = "RenderStop: " ++ show wid
    show (RemoveRendererImage name) = "RemoveRendererImage: " ++ show name
    show ExitApplication{} = "ExitApplication"
    show (UpdateWindow req) = "UpdateWindow: " ++ show req
    show UpdateModel{} = "UpdateModel"
    show (SetWidgetPath wid path) = "SetWidgetPath: " ++ show (wid, path)
    show (ResetWidgetPath wid) = "ResetWidgetPath: " ++ show wid
    show RaiseEvent{} = "RaiseEvent"
    show SendMessage{} = "SendMessage"
    show RunTask{} = "RunTask"
    show RunProducer{} = "RunProducer"
    show RunInRenderThread{} = "RunInRenderThread"
  
  instance Show (WidgetResult s e) where
    show result = "WidgetResult "
      ++ "{ _wrRequests: " ++ show (_wrRequests result)
      ++ ", _wrNode: " ++ show (_wrNode result)
      ++ " }"
  
  instance Show (WidgetEnv s e) where
    show wenv = "WidgetEnv "
      ++ "{ _weOs: " ++ show (_weOs wenv)
      ++ ", _weWindowSize: " ++ show (_weWindowSize wenv)
      ++ ", _weFocusedPath: " ++ show (_weFocusedPath wenv)
      ++ ", _weTimestamp: " ++ show (_weTimestamp wenv)
      ++ " }"
  
  instance Show (WidgetNode s e) where
    show node = "WidgetNode "
      ++ "{ _wnInfo: " ++ show (_wnInfo node)
      ++ ", _wnChildren: " ++ show (_wnChildren node)
      ++ " }"
  