    {-|

    SDL (Simple DirectMedia Layer) is a library for cross-platform development of
    interactive applications. SDL provides routines for managing windows, rendering
    graphics, processing sound, collecting input data, and much more. The Haskell
    @sdl2@ library provides both a high- and low-level API to interface with
    SDL. This module exports the high-level API, whereas "SDL.Raw" provides the
    lower-level bindings.

    -}
    module SDL
      ( -- * Getting Started
        -- $gettingStarted

        -- * Initialization
        module SDL.Init

        -- * Modules
      , module SDL.Audio
      , module SDL.Event
      , module SDL.Filesystem
      , module SDL.Hint
      , module SDL.Input
      , module SDL.Power
      , module SDL.Time
      , module SDL.Vect
      , module SDL.Video

      -- * Error Handling
      , module SDL.Exception

      -- * Working with State Variables
      -- $stateVars
      , get, ($=), ($~)
      -- ** Strict modification
      , ($=!), ($~!)
      ) where

    import Data.StateVar
    import SDL.Audio
    import SDL.Event
    import SDL.Exception
    import SDL.Filesystem
    import SDL.Hint
    import SDL.Init
    import SDL.Input
    import SDL.Power
    import SDL.Time
    import SDL.Vect
    import SDL.Video

    {- $gettingStarted

    The "SDL" module exports a high-level Haskell-like abstraction to use the <http://libsdl.org/ SDL> library. SDL is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D.

    To get started, import "SDL" and begin by initializing the subsystems you need:

    @
    import "SDL"

    main :: IO ()
    main = do
      'initializeAll'
    @

    Next, you can create a 'Window' by using 'createWindow'

    @
      window <- 'createWindow' "My SDL Application" 'defaultWindow'
    @

    If you wish to use SDL's 2D graphics API, you can also create a 'Renderer':

    @
      renderer <- 'createRenderer' window (-1) 'defaultRenderer'
    @

    Then, we enter our main application loop:

    @
      appLoop renderer
    @

    Finally, once our appLoop has returned we destroy the 'Window' using 'destroyWindow':

    @
      'destroyWindow' window
    @

    For the body of your application, we enter a loop. Inside this loop you should begin by collecting all events that
    have happened - these events will inform you about information such as key presses and mouse movement:

    @
    appLoop :: 'Renderer' -> IO ()
    appLoop renderer = do
      events <- 'pollEvents'
    @

    Here @events@ is a list of 'Event' values. For our application we will check if the user pressed the q key, indicating they wish to quit the application

    @
      let eventIsQPress event =
            case 'eventPayload' event of
              'KeyboardEvent' keyboardEvent ->
                'keyboardEventKeyMotion' keyboardEvent == 'Pressed' &&
                'keysymKeycode' ('keyboardEventKeysym' keyboardEvent) == 'KeycodeQ'
              _ -> False
          qPressed = any eventIsQPress events
    @

    In our @appLoop@ we process events and then update the screen accordingly. Here we simply use the 'Renderer'
    to clear the screen to blue:

    @
      'rendererDrawColor' renderer '$=' V4 0 0 255 255
      'clear' renderer
      'present' renderer
    @

    If q was not pressed, we loop again. Otherwise, we exit the loop:

    @
      unless qPressed (appLoop renderer)
    @

    To recap, here is our full application

    @

    \{\-\# LANGUAGE OverloadedStrings \#\-\}
    module "Main" where

    import "SDL"
    import "Linear" (V4(..))
    import "Control.Monad" (unless)

    main :: IO ()
    main = do
      'initializeAll'
      window <- 'createWindow' "My SDL Application" 'defaultWindow'
      renderer <- 'createRenderer' window (-1) 'defaultRenderer'
      appLoop renderer
      destroyWindow window

    appLoop :: 'Renderer' -> IO ()
    appLoop renderer = do
      events <- 'pollEvents'
      let eventIsQPress event =
            case 'eventPayload' event of
              'KeyboardEvent' keyboardEvent ->
                'keyboardEventKeyMotion' keyboardEvent == 'Pressed' &&
                'keysymKeycode' ('keyboardEventKeysym' keyboardEvent) == 'KeycodeQ'
              _ -> False
          qPressed = any eventIsQPress events
      'rendererDrawColor' renderer '$=' V4 0 0 255 255
      'clear' renderer
      'present' renderer
      unless qPressed (appLoop renderer)
    @

    -}

    {- $stateVars

    The SDL API is moderately stateful. For the places where there is state that can be both read and changed, we use an abstraction provided by "Data.StateVar". This module exposes the 'StateVar' type, which models a mutable variable. You can query the contents of a 'StateVar' with 'get', and you can replace the contents of 'StateVar' with the infix assignment operator '$='.

    -}