packages feed

Hate-0.1.4.2: src/Hate/Events.hs

module Hate.Events
    ( initialEventsState
    , setCallbacks
    , fetchEvents
    , allowedEvent
    , module Hate.Events.Types
    )
where

import qualified Graphics.UI.GLFW as GLFW

import Control.Concurrent.STM    (TQueue, atomically, newTQueueIO, tryReadTQueue, writeTQueue)
import Hate.Events.Types
import Hate.Common.Types

import Control.Monad.IO.Class (liftIO)
import Control.Monad.State.Class (gets)
import Control.Applicative
import Data.Maybe

import GHC.Float (double2Float)

initialEventsState :: IO EventsState
initialEventsState = newTQueueIO :: IO (TQueue TimedEvent)

{- The code has been borrowed from GLFW-b-demo; thanks @bsl -}

-- I assume only one window can be used by the framework

time = fromJust <$> GLFW.getTime

writeWithTime :: TQueue TimedEvent -> Event -> IO ()
writeWithTime tc e = time >>= \t -> atomically . writeTQueue tc $ (t, e)

errorCallback           :: TQueue TimedEvent -> GLFW.Error -> String                                                            -> IO ()
windowPosCallback       :: TQueue TimedEvent -> GLFW.Window -> Int -> Int                                                       -> IO ()
windowSizeCallback      :: TQueue TimedEvent -> GLFW.Window -> Int -> Int                                                       -> IO ()
windowCloseCallback     :: TQueue TimedEvent -> GLFW.Window                                                                     -> IO ()
windowRefreshCallback   :: TQueue TimedEvent -> GLFW.Window                                                                     -> IO ()
windowFocusCallback     :: TQueue TimedEvent -> GLFW.Window -> GLFW.FocusState                                                  -> IO ()
windowIconifyCallback   :: TQueue TimedEvent -> GLFW.Window -> GLFW.IconifyState                                                -> IO ()
framebufferSizeCallback :: TQueue TimedEvent -> GLFW.Window -> Int -> Int                                                       -> IO ()
mouseButtonCallback     :: TQueue TimedEvent -> GLFW.Window -> GLFW.MouseButton   -> GLFW.MouseButtonState -> GLFW.ModifierKeys -> IO ()
cursorPosCallback       :: TQueue TimedEvent -> GLFW.Window -> Double -> Double                                                 -> IO ()
cursorEnterCallback     :: TQueue TimedEvent -> GLFW.Window -> GLFW.CursorState                                                 -> IO ()
scrollCallback          :: TQueue TimedEvent -> GLFW.Window -> Double -> Double                                                 -> IO ()
keyCallback             :: TQueue TimedEvent -> GLFW.Window -> GLFW.Key -> Int -> GLFW.KeyState -> GLFW.ModifierKeys            -> IO ()
charCallback            :: TQueue TimedEvent -> GLFW.Window -> Char                                                             -> IO ()

errorCallback           tc e s            = writeWithTime tc $ EventError           e s
windowPosCallback       tc _ x y          = writeWithTime tc $ EventWindowPos       x y
windowSizeCallback      tc _ w h          = writeWithTime tc $ EventWindowSize      w h
windowCloseCallback     tc _              = writeWithTime tc $ EventWindowClose
windowRefreshCallback   tc _              = writeWithTime tc $ EventWindowRefresh
windowFocusCallback     tc _ fa           = writeWithTime tc $ EventWindowFocus     fa
windowIconifyCallback   tc _ ia           = writeWithTime tc $ EventWindowIconify   ia
framebufferSizeCallback tc _ w h          = writeWithTime tc $ EventFramebufferSize w h
mouseButtonCallback     tc _ mb mba mk    = writeWithTime tc $ EventMouseButton     mb mba mk
cursorPosCallback       tc _ x y          = writeWithTime tc $ EventCursorPos       (double2Float x) (double2Float y)
cursorEnterCallback     tc _ ca           = writeWithTime tc $ EventCursorEnter     ca
scrollCallback          tc _ x y          = writeWithTime tc $ EventScroll          x y
keyCallback             tc _ k sc ka mk   = writeWithTime tc $ EventKey             k sc ka mk
charCallback            tc _ c            = writeWithTime tc $ EventChar            c

setErrorCallback :: TQueue TimedEvent -> IO ()
setErrorCallback eventsChan = GLFW.setErrorCallback $ Just $ errorCallback eventsChan

setCallbacks :: EventsState -> GLFW.Window -> IO ()
setCallbacks eventsChan win = do
    GLFW.setWindowPosCallback       win $ Just $ windowPosCallback       eventsChan
    GLFW.setWindowSizeCallback      win $ Just $ windowSizeCallback      eventsChan
    GLFW.setWindowCloseCallback     win $ Just $ windowCloseCallback     eventsChan
    GLFW.setWindowRefreshCallback   win $ Just $ windowRefreshCallback   eventsChan
    GLFW.setWindowFocusCallback     win $ Just $ windowFocusCallback     eventsChan
    GLFW.setWindowIconifyCallback   win $ Just $ windowIconifyCallback   eventsChan
    GLFW.setFramebufferSizeCallback win $ Just $ framebufferSizeCallback eventsChan
    GLFW.setMouseButtonCallback     win $ Just $ mouseButtonCallback     eventsChan
    GLFW.setCursorPosCallback       win $ Just $ cursorPosCallback       eventsChan
    GLFW.setCursorEnterCallback     win $ Just $ cursorEnterCallback     eventsChan
    GLFW.setScrollCallback          win $ Just $ scrollCallback          eventsChan
    GLFW.setKeyCallback             win $ Just $ keyCallback             eventsChan
    GLFW.setCharCallback            win $ Just $ charCallback            eventsChan

fetchEvents :: HateInner us [TimedEvent]
fetchEvents = fetchEvents' []
    where 
        fetchEvents' :: [TimedEvent] -> HateInner us [TimedEvent]
        fetchEvents' xs = do
            tc <- gets (eventsState . libraryState)
            me <- liftIO $ atomically $ tryReadTQueue tc
            case me of
                Just e -> fetchEvents' (e:xs)
                Nothing -> return xs

-- | Some events aren't meant to impact the user, and should be handled
-- internally by framework instead.

allowedEvent :: Event -> Bool
allowedEvent (EventWindowClose)       = True
allowedEvent (EventWindowFocus _)     = True
allowedEvent (EventMouseButton _ _ _) = True
allowedEvent (EventCursorPos _ _)     = True
allowedEvent (EventScroll _ _)        = True
allowedEvent (EventKey _ _ _ _)       = True
allowedEvent (EventChar _)            = True
allowedEvent _ = False