packages feed

gruff-0.1: GLUTGtk.hs

module GLUTGtk where

import Control.Monad (join)
import Control.Monad.Trans (liftIO)
import Data.IORef (IORef, newIORef, readIORef)
import Graphics.UI.Gtk hiding (Size)
import Graphics.UI.Gtk.OpenGL

type RealizeCallback = IO ()
type ReshapeCallback = Size -> IO ()
type DisplayCallback = IO ()
type KeyboardMouseCallback = Key -> KeyState -> [Modifier] -> Position -> IO ()

data Size = Size Int Int
  deriving (Eq, Ord, Show)

data Position = Position Double Double
  deriving (Eq, Ord, Show)

data KeyState = Down | Up
  deriving (Eq, Ord, Show)

data Key = Char Char | MouseButton MouseButton
  deriving (Eq, Show)

data GLUTGtk = GLUTGtk
  { realizeCallback :: IORef RealizeCallback
  , reshapeCallback :: IORef ReshapeCallback
  , displayCallback :: IORef DisplayCallback
  , keyboardMouseCallback :: IORef KeyboardMouseCallback
  , postRedisplay :: IO ()
  , widget :: EventBox
  }

glut :: Size -> IO GLUTGtk
glut (Size width height) = do
  realizeCallback' <- newIORef $ return ()
  displayCallback' <- newIORef $ return ()
  reshapeCallback' <- newIORef $ \_ -> return ()
  keyboardMouseCallback' <- newIORef $ \_ _ _ _ -> return ()
  config <- glConfigNew [ GLModeRGBA, GLModeDouble ]
  canvas <- glDrawingAreaNew config
  widgetSetSizeRequest canvas width height
  eventb <- eventBoxNew
  set eventb [ containerBorderWidth := 0, containerChild := canvas ]
  _ <- onRealize canvas $ withGLDrawingArea canvas $ \_ -> join (readIORef realizeCallback')
  _ <- canvas `on` configureEvent $ tryEvent $ do
    (w, h) <- eventSize
    liftIO $ do
      cb <- readIORef reshapeCallback'
      cb (Size w h)
  _ <- canvas `on` exposeEvent $ tryEvent $ liftIO $ withGLDrawingArea canvas $ \gl -> do
    join (readIORef displayCallback')
    glDrawableSwapBuffers gl
  let handleButton s = do
        b <- eventButton
        (x, y) <- eventCoordinates
        ms <- eventModifier
        liftIO $ do
          cb <- readIORef keyboardMouseCallback'
          cb (MouseButton b) s ms (Position x y)
  _ <- eventb `on` buttonPressEvent   $ tryEvent $ handleButton Down
  _ <- eventb `on` buttonReleaseEvent $ tryEvent $ handleButton Up
  return $ GLUTGtk
    { realizeCallback = realizeCallback'
    , displayCallback = displayCallback'
    , reshapeCallback = reshapeCallback'
    , keyboardMouseCallback = keyboardMouseCallback'
    , postRedisplay = widgetQueueDraw canvas
    , widget = eventb
    }