content: {-# OPTIONS -fspec-constr-count=5 #-}
  {-# LANGUAGE Rank2Types #-}
  
  module Brillo.Internals.Interface.Backend.Types (
    module Brillo.Internals.Interface.Backend.Types,
    module Brillo.Data.Display,
  )
  where
  
  import Brillo.Data.Display
  import Brillo.Data.FileDialog (FileDialog)
  import Data.IORef (IORef)
  
  
  {-| The functions every backend window managed backend needs to support.
  
    The Backend module interfaces with the window manager, and handles opening
    and closing the window, and managing key events etc.
  
    It doesn't know anything about drawing lines or setting colors.
    When we get a display callback, Brillo will perform OpenGL actions, and
    the backend needs to have OpenGL in a state where it's able to accept them.
  -}
  class Backend a where
    -- | Initialize the state used by the backend.
    -- If you don't use any state, make a Unit-like type.
    initBackendState :: a
  
  
    -- | Perform any initialization that needs to happen before opening a window
    --   The Boolean flag indicates if any debug information should be printed to
    --   the terminal
    initializeBackend :: IORef a -> Bool -> IO ()
  
  
    -- | Perform any deinitialization and close the backend.
    exitBackend :: IORef a -> IO ()
  
  
    -- | Open a window with the given display mode.
    openWindow :: IORef a -> Display -> IO ()
  
  
    -- | Dump information about the backend to the terminal.
    dumpBackendState :: IORef a -> IO ()
  
  
    -- | Install the display callbacks.
    installDisplayCallback :: IORef a -> [Callback] -> IO ()
  
  
    -- | Install the window close callback.
    installWindowCloseCallback :: IORef a -> IO ()
  
  
    -- | Install the reshape callbacks.
    installReshapeCallback :: IORef a -> [Callback] -> IO ()
  
  
    -- | Install the keymouse press callbacks.
    installKeyMouseCallback :: IORef a -> [Callback] -> IO ()
  
  
    -- | Install the mouse motion callbacks.
    installMotionCallback :: IORef a -> [Callback] -> IO ()
  
  
    -- | Install the file/directory drop callbacks.
    installDropCallback :: IORef a -> [Callback] -> IO ()
  
  
    -- | Install the idle callbacks.
    installIdleCallback :: IORef a -> [Callback] -> IO ()
  
  
    -- | The mainloop of the backend.
    runMainLoop :: IORef a -> IO ()
  
  
    -- | A function that signals that screen has to be updated.
    postRedisplay :: IORef a -> IO ()
  
  
    -- | Function that returns (width,height) of the window in pixels.
    getWindowDimensions :: IORef a -> IO (Int, Int)
  
  
    -- | Function that returns (width,height) of a fullscreen window in pixels.
    getScreenSize :: IORef a -> IO (Int, Int)
  
  
    -- | Open a file dialog to pick files/directories.
    openFileDialog :: IORef a -> FileDialog -> IO (Maybe [FilePath])
  
  
    -- | Function that reports the time elapsed since the application started.
    --   (in seconds)
    elapsedTime :: IORef a -> IO Double
  
  
    -- | Function that puts the current thread to sleep for 'n' seconds.
    sleep :: IORef a -> Double -> IO ()
  
  
  -- The callbacks should work for all backends. We pass a reference to the
  -- backend state so that the callbacks have access to the class dictionary and
  -- can thus call the appropriate backend functions.
  
  -- | Display callback has no arguments.
  type DisplayCallback =
    forall a. (Backend a) => IORef a -> IO ()
  
  
  -- | Arguments: KeyType, Key Up \/ Down, Ctrl \/ Alt \/ Shift pressed, latest mouse location.
  type KeyboardMouseCallback =
    forall a.
    (Backend a) =>
    IORef a ->
    Key ->
    KeyState ->
    Modifiers ->
    (Int, Int) ->
    IO ()
  
  
  -- | No arguments.
  type IdleCallback =
    forall a. (Backend a) => IORef a -> IO ()
  
  
  -- | Arguments: (PosX,PosY) in pixels.
  type MotionCallback =
    forall a. (Backend a) => IORef a -> (Int, Int) -> IO ()
  
  
  -- | Arguments: [FilePath] of dropped files.
  type DropCallback =
    forall a. (Backend a) => IORef a -> [FilePath] -> IO ()
  
  
  -- | Arguments: (Width,Height) in pixels.
  type ReshapeCallback =
    forall a. (Backend a) => IORef a -> (Int, Int) -> IO ()
  
  
  -------------------------------------------------------------------------------
  data Callback
    = Display DisplayCallback
    | KeyMouse KeyboardMouseCallback
    | Idle IdleCallback
    | Motion MotionCallback
    | Drop DropCallback
    | Reshape ReshapeCallback
  
  
  -- | Check if this is an `Idle` callback.
  isIdleCallback :: Callback -> Bool
  isIdleCallback cc =
    case cc of
      Idle _ -> True
      _ -> False
  
  
  -------------------------------------------------------------------------------
  -- This is Brillo's view of mouse and keyboard events.
  -- The actual events provided by the backends are converted to this form
  -- by the backend module.
  
  data Key
    = Char Char
    | SpecialKey SpecialKey
    | MouseButton MouseButton
    deriving (Show, Eq, Ord)
  
  
  data MouseButton
    = LeftButton
    | MiddleButton
    | RightButton
    | WheelUp
    | WheelDown
    | AdditionalButton Int
    deriving (Show, Eq, Ord)
  
  
  data KeyState
    = Down
    | Up
    deriving (Show, Eq, Ord)
  
  
  data SpecialKey
    = KeyUnknown
    | KeySpace
    | KeyEsc
    | KeyF1
    | KeyF2
    | KeyF3
    | KeyF4
    | KeyF5
    | KeyF6
    | KeyF7
    | KeyF8
    | KeyF9
    | KeyF10
    | KeyF11
    | KeyF12
    | KeyF13
    | KeyF14
    | KeyF15
    | KeyF16
    | KeyF17
    | KeyF18
    | KeyF19
    | KeyF20
    | KeyF21
    | KeyF22
    | KeyF23
    | KeyF24
    | KeyF25
    | KeyUp
    | KeyDown
    | KeyLeft
    | KeyRight
    | KeyTab
    | KeyEnter
    | KeyBackspace
    | KeyInsert
    | KeyNumLock
    | KeyBegin
    | KeyDelete
    | KeyPageUp
    | KeyPageDown
    | KeyHome
    | KeyEnd
    | KeyShiftL
    | KeyShiftR
    | KeyCtrlL
    | KeyCtrlR
    | KeyAltL
    | KeyAltR
    | KeyPad0
    | KeyPad1
    | KeyPad2
    | KeyPad3
    | KeyPad4
    | KeyPad5
    | KeyPad6
    | KeyPad7
    | KeyPad8
    | KeyPad9
    | KeyPadDivide
    | KeyPadMultiply
    | KeyPadSubtract
    | KeyPadAdd
    | KeyPadDecimal
    | KeyPadEqual
    | KeyPadEnter
    deriving (Show, Eq, Ord)
  
  
  data Modifiers
    = Modifiers
    { shift :: KeyState
    , ctrl :: KeyState
    , alt :: KeyState
    }
    deriving (Show, Eq, Ord)
  