gluturtle-0.0.4: src/Graphics/UI/GLUT/Turtle/Field.hs
{-# LANGUAGE DoRec #-}
module Graphics.UI.GLUT.Turtle.Field(
-- * types and classes
Field,
Layer,
Character,
Coordinates(..),
-- * basic functions
openField,
closeField,
waitField,
topleft,
center,
coordinates,
fieldSize,
-- * draw
forkField,
flushField,
fieldColor,
-- ** to Layer
drawLine,
fillRectangle,
fillPolygon,
writeString,
drawImage,
undoLayer,
undoField,
clearLayer,
-- ** to Character
drawCharacter,
drawCharacterAndLine,
clearCharacter,
-- * event driven
oninputtext,
onclick,
onrelease,
ondrag,
onmotion,
onkeypress,
ontimer,
addLayer,
addCharacter
) where
import System.Exit
import Control.Applicative
import Graphics.UI.GLUT.Turtle.Triangles
import Graphics.UI.GLUT(
createWindow, Vertex2(..), renderPrimitive, vertex, PrimitiveMode(..),
preservingMatrix, GLfloat, swapBuffers, ($=), displayCallback,
initialDisplayMode, initialWindowSize, Size(..),
DisplayMode(..), flush, Vertex3(..)
)
import qualified Graphics.UI.GLUT as G
import Graphics.UI.GLUT.Turtle.Layers(
Layers, Layer, Character, newLayers, redrawLayers,
makeLayer, background, addDraw, undoLayer, clearLayer,
makeCharacter, character)
import Text.XML.YJSVG(Position(..), Color(..))
import Control.Monad(when, unless, forever, replicateM, forM_, join)
import Control.Monad.Tools(doWhile_, doWhile)
import Control.Arrow((***))
import Control.Concurrent(
ThreadId, forkIO, killThread, threadDelay,
Chan, newChan, readChan, writeChan)
import Data.IORef(IORef, newIORef, readIORef, writeIORef)
import Data.IORef.Tools(atomicModifyIORef_)
import Data.Maybe(fromMaybe)
import Data.List(delete)
import Data.Convertible(convert)
import Data.Function.Tools(const2, const3)
--------------------------------------------------------------------------------
data Coordinates = CoordTopLeft | CoordCenter
data Field = Field{
fCoordinates :: Coordinates,
fAction :: IORef (IO ()),
fActions :: IORef [IO ()],
fString :: IORef String,
fString2 :: IORef String,
fInputtext :: IORef (String -> IO Bool),
fLayers :: IORef Layers
}
addLayer = makeLayer . fLayers
addCharacter = makeCharacter . fLayers
--------------------------------------------------------------------------------
undoField :: Field -> IO ()
undoField f = atomicModifyIORef_ (fActions f) tail
openField :: IO Field
openField = do
layers <- newLayers 0 (return ()) (return ()) (return ())
action <- newIORef $ return ()
actions <- newIORef []
str <- newIORef ""
str2 <- newIORef "coi rodo"
inputtext <- newIORef $ const $ return True
initialDisplayMode $= [RGBMode, DoubleBuffered]
initialWindowSize $= Size 640 480
createWindow "field"
displayCallback $= (do
sequence_ =<< readIORef actions) -- testAction
G.addTimerCallback 10 (timerAction $ do
G.clearColor $= G.Color4 0 0 0 0
G.clear [G.ColorBuffer]
sequence_ =<< readIORef actions
join $ readIORef action
G.lineWidth $= 1.0
preservingMatrix $ do
G.scale (0.0005 :: GLfloat) 0.0005 0.0005
G.clearColor $= G.Color4 0 0 0 0
G.color (G.Color4 0 1 0 0 :: G.Color4 GLfloat)
w <- G.stringWidth G.Roman "Stroke font"
G.translate (G.Vector3 (-2.5 * (fromIntegral w))
(-1600) 0 ::
G.Vector3 GLfloat)
G.renderString G.Roman =<< readIORef str
preservingMatrix $ do
G.scale (0.0005 :: GLfloat) 0.0005 0.0005
G.clearColor $= G.Color4 0 0 0 0
G.color (G.Color4 0 1 0 0 :: G.Color4 GLfloat)
w <- G.stringWidth G.Roman "Stroke font"
G.translate (G.Vector3 (-2.5 * (fromIntegral w))
(-1400) 0 ::
G.Vector3 GLfloat)
G.renderString G.Roman =<< readIORef str2
swapBuffers)
G.reshapeCallback $= Just (\size -> G.viewport $= (G.Position 0 0, size))
print "main loop go"
print "main loop"
let f = Field{
fCoordinates = CoordCenter,
fLayers = layers,
fAction = action,
fActions = actions,
fString = str,
fString2 = str2,
fInputtext = inputtext
}
G.keyboardMouseCallback $= Just (keyboardProc f)
return f
timerAction act = do
act
G.addTimerCallback 10 $ timerAction act
data InputType = XInput | End | Timer
waitInput :: Field -> IO (Chan ())
waitInput f = newChan
closeField :: Field -> IO ()
closeField _ = return ()
waitField :: Field -> IO ()
waitField = const $ return ()
topleft, center :: Field -> IO ()
topleft = const $ return ()
center = const $ return ()
coordinates :: Field -> IO Coordinates
coordinates = return . fCoordinates
fieldSize :: Field -> IO (Double, Double)
fieldSize = const $ return (0, 0)
--------------------------------------------------------------------------------
forkField :: Field -> IO () -> IO ThreadId
forkField f act = do
tid <- forkIO act
return tid
flushField :: Field -> Bool -> IO a -> IO a
flushField f real act = act
fieldColor :: Field -> Layer -> Color -> IO ()
fieldColor f l clr = return ()
--------------------------------------------------------------------------------
drawLayer f l drw = addDraw l (drw, drw)
drawLine :: Field -> Layer -> Double -> Color -> Position -> Position -> IO ()
drawLine f l w c p q = do
atomicModifyIORef_ (fActions f) (makeLineAction p q c w :)
-- G.addTimerCallback 1 $ makeLineAction p q c
-- swapBuffers
flush
{- do
preservingMatrix $ do
renderPrimitive Quads $ mapM_ vertex [
Vertex3 0.10 0.10 0.0,
Vertex3 (-0.10) 0.10 0.0,
Vertex3 (-0.10) (-0.10) 0.0,
Vertex3 0.10 (-0.10) 0.0 :: Vertex3 GLfloat
]
swapBuffers -}
testAction = do
G.loadIdentity
preservingMatrix $ do
renderPrimitive Lines $ mapM_ vertex [
Vertex3 0.10 0.10 0.0,
Vertex3 (-0.10) 0.10 0.0,
Vertex3 (-0.10) (-0.10) 0.0,
Vertex3 0.10 (-0.10) 0.0 :: Vertex3 GLfloat
]
-- swapBuffers
makeLineAction :: Position -> Position -> Color -> Double -> IO ()
makeLineAction p q c w = do
preservingMatrix $ do
G.lineWidth $= fromRational (toRational w)
G.color $ colorToColor4 c -- (G.Color4 1 0 0 0 :: G.Color4 GLfloat)
renderPrimitive Lines $ mapM_ vertex [
positionToVertex3 p,
positionToVertex3 q ]
-- swapBuffers
colorToColor4 :: Color -> G.Color4 GLfloat
colorToColor4 (RGB r g b) = G.Color4
(fromIntegral r / 255) (fromIntegral g / 255) (fromIntegral b / 255) 0
makeCharacterAction :: [Position] -> Color -> Color -> Double -> IO ()
makeCharacterAction ps c lc lw =
preservingMatrix $ do
print ps
G.color $ colorToColor4 c
renderPrimitive Triangles $ mapM_ (vertex . positionToVertex3) $
map posToPosition $ triangleToPositions $
toTriangles $ map positionToPos ps
-- renderPrimitive Polygon $ mapM_ (vertex . positionToVertex3) ps
G.lineWidth $= fromRational (toRational lw)
G.color $ colorToColor4 lc
renderPrimitive LineLoop $ mapM_ (vertex . positionToVertex3) ps
type Pos = (Double, Double)
triangleToPositions :: [(Pos, Pos, Pos)] -> [Pos]
triangleToPositions [] = []
triangleToPositions ((a, b, c) : rest) = a : b : c : triangleToPositions rest
positionToPos :: Position -> Pos
positionToPos (Center x y) = (x, y)
posToPosition :: Pos -> Position
posToPosition (x, y) = Center x y
positionToVertex3 :: Position -> Vertex2 GLfloat
positionToVertex3 (Center x y) =
Vertex2 (fromRational $ toRational x / 300)
(fromRational $ toRational y / 300 + 0.2)
writeString :: Field -> Layer -> String -> Double -> Color -> Position ->
String -> IO ()
writeString f l fname size clr pos str = return ()
drawImage :: Field -> Layer -> FilePath -> Position -> Double -> Double -> IO ()
drawImage f l fp pos w h = return ()
fillRectangle :: Field -> Layer -> Position -> Double -> Double -> Color -> IO ()
fillRectangle f l p w h clr = return ()
fillPolygon :: Field -> Layer -> [Position] -> Color -> Color -> Double -> IO ()
fillPolygon f l ps clr lc lw = do
atomicModifyIORef_ (fActions f) (makeCharacterAction ps clr lc lw :)
--------------------------------------------------------------------------------
drawCharacter :: Field -> Character -> Color -> Color -> [Position] -> Double -> IO ()
drawCharacter f ch fc c ps lw = return ()
drawCharacterAndLine :: Field -> Character -> Color -> Color -> [Position] ->
Double -> Position -> Position -> IO ()
drawCharacterAndLine f ch fclr clr sh lw p q =
writeIORef (fAction f) $ do
makeLineAction p q clr lw
makeCharacterAction sh fclr clr lw
clearCharacter :: Character -> IO ()
clearCharacter ch = character ch $ return ()
--------------------------------------------------------------------------------
oninputtext :: Field -> (String -> IO Bool) -> IO ()
oninputtext = writeIORef . fInputtext
onclick, onrelease :: Field -> (Int -> Double -> Double -> IO Bool) -> IO ()
onclick _ _ = return ()
onrelease _ _ = return ()
ondrag :: Field -> (Int -> Double -> Double -> IO ()) -> IO ()
ondrag _ _ = return ()
onmotion :: Field -> (Double -> Double -> IO ()) -> IO ()
onmotion _ _ = return ()
onkeypress :: Field -> (Char -> IO Bool) -> IO ()
onkeypress _ _ = return ()
ontimer :: Field -> Int -> IO Bool -> IO ()
ontimer f t fun = return ()
keyboardProc :: Field -> G.Key -> G.KeyState -> G.Modifiers -> G.Position -> IO ()
keyboardProc f (G.Char 'q') _ _ _ = exitWith ExitSuccess
keyboardProc f (G.Char '\r') G.Down _ _ = do
str <- readIORef $ fString f
($ str) =<< readIORef (fInputtext f)
writeIORef (fString2 f) str
writeIORef (fString f) ""
keyboardProc f (G.Char '\b') G.Down _ _ = atomicModifyIORef_ (fString f) init
keyboardProc f (G.Char c) state _ _
| state == G.Down = print c >> atomicModifyIORef_ (fString f) (++ [c])
| otherwise = return ()
keyboardProc _ _ _ _ _ = return ()