packages feed

wxturtle-0.0.1: src/Graphics/UI/WX/Turtle/Field.hs

{-# LANGUAGE DoRec #-}

module Graphics.UI.WX.Turtle.Field(
	-- * types and classes
	Field(fFrame),
	Layer,
	Character,
	Coordinates(..),

	-- * basic functions
	openField,
	closeField,
	waitField,
	topleft,
	center,
	coordinates,
	fieldSize,

	-- * draw
	forkField,
	flushField,
	fieldColor,

	-- ** to Layer
	addLayer,
	drawLine,
	fillRectangle,
	fillPolygon,
	writeString,
	drawImage,
	undoLayer,
	undoField,
	clearLayer,

	-- ** to Character
	addCharacter,
	drawCharacter,
	drawCharacterAndLine,
	clearCharacter,

	-- * event driven
	oninputtext,
	onclick,
	onrelease,
	ondrag,
	onmotion,
	onkeypress,
	ontimer
) where

import Graphics.UI.WX(
	on, command, Prop(..), text, button, frame, layout, widget, set, panel,
	Frame, Panel, minsize, sz, column, circle, paint, Point2(..), Point,
	line, repaint, DC, Rect, dcClear, polygon, red, green, brushColor, penColor,
	rgb, row, textEntry, processEnter, get, hfill, fill, size, Size2D(..), resize,
	TextCtrl, penWidth
 )
import qualified Graphics.UI.WX as WX

import Graphics.UI.WX.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{
	fFrame :: Frame (),
	fPanel :: Panel (),
	fAction :: IORef (DC () -> Rect -> IO ()),
	fActions :: IORef [DC () -> Rect -> IO ()],
	fCharacter :: Character,
	fCoordinates :: Coordinates,

	fPenColor :: (Int, Int, Int),
	fDrawColor :: (Int, Int, Int),

	fSize :: IORef (Double, Double),

	fInputtext :: IORef (String -> IO Bool),

	fLayers :: IORef Layers
 }

--------------------------------------------------------------------------------

undoField :: Field -> IO ()
undoField f = do
	atomicModifyIORef_ (fActions f) tail

openField :: IO Field
openField = do
	fr <- frame [text := "turtle"]
	p <- panel fr []
	quit <- button fr [text := "Quit", on command := WX.close fr]
	inputAction <- newIORef $ \_ -> return True
	rec input <- textEntry fr [
		processEnter := True,
		on command := do
			str <- get input text
			putStrLn str
			set input [text := ""]
			cont <- ($ str) =<< readIORef inputAction
			when (not cont) $ WX.close fr]
	set fr [layout := column 5 [
		fill $ minsize (sz 300 300) $ widget p,
		row 5 [hfill $ widget input] ]] -- , widget quit] ]]
	act <- newIORef $ \dc rct -> circle dc (Point 40 25) 25 []
	acts <- newIORef []
	layers <- newLayers 50 (return ())
--		(writeIORef act (\dc rect -> dcClear dc) >> repaint p)
		(return ())
		(return ())
--		(writeIORef act (\dc rect -> dcClear dc) >> repaint p)
--		(return ())
	Size x y <- get p size
	print x
	print y
	sz <- newIORef (fromIntegral x, fromIntegral y)
	let	f = Field{
			fFrame = fr,
			fPanel = p,
			fAction = act,
			fActions = acts,
			fCoordinates = CoordCenter,
			fPenColor = (0, 0, 0),
			fSize = sz,
			fLayers = layers,
			fInputtext = inputAction
		 }
	set p [	on paint := \dc rct -> do
			act <- readIORef $ fAction f
			acts <- readIORef $ fActions f
			mapM_ (($ rct) . ($ dc)) acts
			act dc rct,
		on resize := do
			Size x y <- get p size
			writeIORef sz (fromIntegral x, fromIntegral y) ]
	return f

data InputType = XInput | End | Timer

waitInput :: Field -> IO (Chan ())
waitInput f = newChan

closeField :: Field -> IO ()
closeField = WX.close . fFrame

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 ()

--------------------------------------------------------------------------------

addLayer = makeLayer . fLayers

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) $ (act :)
	repaint $ fPanel f
	where
	act = \dc rect -> do 
		set dc [penColor := colorToWX c, penWidth := round w]
		p' <- positionToPoint f p
		q' <- positionToPoint f q
		line dc p' q' []

getPenColor :: Field -> WX.Color
getPenColor Field{fPenColor = (r, g, b)} = rgb r g b

colorToWX :: Color -> WX.Color
colorToWX (RGB{colorRed = r, colorGreen = g, colorBlue = b}) = rgb r g b

{- addDraw l (do
	atomicModifyIORef_ (fAction f) $ \f dc rect -> do
		f dc rect
		line dc (positionToPoint p) (positionToPoint q) []
	repaint $ fPanel f, do
	atomicModifyIORef_ (fAction f) $ \f dc rect -> do
		f dc rect
		line dc (positionToPoint p) (positionToPoint q) []
	repaint $ fPanel f)
-}

positionToPoint :: Field -> Position -> IO Point
positionToPoint f (Center x y) = do
	(sx, sy) <- readIORef $ fSize f
	return $ Point (round $ x + sx / 2) (round $ - y + sy / 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) $ (act :)
	repaint $ fPanel f
	where
	act = \dc rect -> do
		set dc [brushColor := colorToWX clr, penColor := colorToWX lc,
			penWidth := round lw]
		sh' <- mapM (positionToPoint f) ps
		polygon dc sh' []

--------------------------------------------------------------------------------

addCharacter = makeCharacter . fLayers

drawCharacter :: Field -> Character -> Color -> Color -> [Position] -> Double -> IO ()
drawCharacter f ch fc c ps lw = do
	writeIORef (fAction f) $ \dc rect -> do
		set dc [brushColor := colorToWX fc, penColor := colorToWX c,
			penWidth := round lw]
		sh' <- mapM (positionToPoint f) ps
		polygon dc sh' []
	repaint $ fPanel f

drawCharacterAndLine ::	Field -> Character -> Color -> Color -> [Position] ->
	Double -> Position -> Position -> IO ()
drawCharacterAndLine f ch fclr clr sh lw p q = do
--	putStrLn $ "drawCharacterAndLine" ++ show p ++ " : " ++ show q
	writeIORef (fAction f) $ \dc rect -> do
		set dc [brushColor := colorToWX fclr, penColor := colorToWX clr,
			penWidth := round lw]
		p' <- positionToPoint f p
		q' <- positionToPoint f q
		line dc p' q' []
		sh' <- mapM (positionToPoint f) sh
		polygon dc sh' []
	repaint $ fPanel f
		
{-
	atomicModifyIORef_ (fAction f) $ \f dc rect -> do
		f dc rect
		line dc (positionToPoint p) (positionToPoint q) []
-}
	repaint $ fPanel f

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 ()