xturtle 0.1.6 → 0.1.9
raw patch · 9 files changed
+537/−553 lines, 9 filesdep ~yjsvgdep ~yjtools
Dependency ranges changed: yjsvg, yjtools
Files
- src/Graphics/X11/Turtle.hs +157/−159
- src/Graphics/X11/Turtle/Data.hs +2/−1
- src/Graphics/X11/Turtle/Field.hs +127/−133
- src/Graphics/X11/Turtle/Input.hs +70/−89
- src/Graphics/X11/Turtle/Layers.hs +42/−43
- src/Graphics/X11/Turtle/Move.hs +62/−66
- src/Graphics/X11/Turtle/State.hs +47/−37
- src/Graphics/X11/Turtle/XTools.hs +27/−22
- xturtle.cabal +3/−3
src/Graphics/X11/Turtle.hs view
@@ -1,7 +1,8 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE RankNTypes #-} -module Graphics.X11.Turtle (+module Graphics.X11.Turtle( -- * meta data xturtleVersion, @@ -10,14 +11,31 @@ Turtle, ColorClass, - -- * beginings and endings+ -- * Field functions+ -- ** meta openField, closeField, waitField,+ topleft,+ center,++ -- ** on events+ onclick,+ onrelease,+ ondrag,+ onmotion,+ onkeypress,+ ontimer,++ -- * Turtle functions+ -- ** meta newTurtle, killTurtle,+ inputs,+ runInputs,+ getSVG, - -- * move turtle+ -- ** move turtle forward, backward, goto,@@ -27,62 +45,51 @@ right, setheading, circle,- write,- stamp,- dot,- image,- bgcolor, home,- clear, undo, sleep,- flushoff,- flushon, flush, - -- * change turtle state+ -- ** draw+ dot,+ stamp,+ beginfill,+ endfill,+ write,+ image,+ bgcolor,+ clear,++ -- ** change states addshape,+ beginpoly,+ endpoly, getshapes, shape, shapesize,- speed, hideturtle, showturtle, penup, pendown,- beginfill,- endfill,- beginpoly,- endpoly, pencolor, pensize,- degrees, radians,+ degrees,+ speed,+ flushoff,+ flushon, - -- * turtle information+ -- ** informations position, xcor, ycor,+ distance, heading, towards,- distance, isdown, isvisible, windowWidth,- windowHeight,-- -- * on events- onclick,- onrelease,- ondrag,- onmotion,- onkeypress,- ontimer,-- -- * save and load- getInputs,- sendInputs,- getSVG+ windowHeight ) where import Graphics.X11.Turtle.Data(shapeTable, speedTable)@@ -91,37 +98,32 @@ turtleSeries, direction, visible, undonum, drawed, polyPoints) import qualified Graphics.X11.Turtle.Input as S(position, degrees, pendown) import Graphics.X11.Turtle.Move(- Field, Layer, Character,- openField, closeField, forkField, waitField, fieldSize, flushField,- moveTurtle, addLayer, clearLayer, addCharacter, clearCharacter,+ Field, Coordinates(..), openField, closeField, fieldSize,+ coordinates, topleft, center, waitField, forkField, flushField,+ addLayer, clearLayer, addCharacter, clearCharacter, moveTurtle, onclick, onrelease, ondrag, onmotion, onkeypress, ontimer)-import Text.XML.YJSVG(SVG(..), Color(..))+import Text.XML.YJSVG(SVG(..), Position(..), Color(..))+import qualified Text.XML.YJSVG as S(center, topleft) -import Control.Concurrent(Chan, writeChan, ThreadId, killThread)+import Control.Concurrent(killThread, writeChan) import Control.Monad(replicateM_, zipWithM_)-import Data.IORef(IORef, newIORef, readIORef, modifyIORef)+import Control.Arrow((&&&))+import Data.IORef(IORef, newIORef, readIORef) import Data.IORef.Tools(atomicModifyIORef_) import Data.Fixed(mod')-import Data.Maybe(fromJust) -------------------------------------------------------------------------------- xturtleVersion :: (Int, String)-xturtleVersion = (56, "0.1.6")+xturtleVersion = (65, "0.1.9") -------------------------------------------------------------------------------- data Turtle = Turtle {- field :: Field,- layer :: Layer,- character :: Character,- inputChan :: Chan TurtleInput,- states :: [TurtleState],- inputs :: [TurtleInput],- stateIndex :: IORef Int,- thread :: ThreadId,- shapes :: IORef [(String, [(Double, Double)])]- }+ field :: Field, input :: TurtleInput -> IO (),+ info :: forall a . (TurtleState -> a) -> IO a,+ shapes :: IORef [(String, [(Double, Double)])],+ inputs :: IO [TurtleInput], killTurtle :: IO ()} class ColorClass a where getColor :: a -> Color @@ -135,35 +137,34 @@ newTurtle :: Field -> IO Turtle newTurtle f = do- l <- addLayer f- ch <- addCharacter f- (ic, tis, sts) <- turtleSeries- si <- newIORef 1- tid <- forkField f $ zipWithM_ (moveTurtle f ch l) sts $ tail sts- shps <- newIORef shapeTable- let t = Turtle {- field = f,- layer = l,- character = ch,- inputChan = ic,- states = sts,- inputs = tis,- stateIndex = si,- thread = tid,- shapes = shps}- shape t "classic" >> input t (Undonum 0)- return t+ index <- newIORef 1; shapesRef <- newIORef shapeTable+ (chan, hist, states) <- turtleSeries+ l <- addLayer f; c <- addCharacter f+ thr <- forkField f $ zipWithM_ (moveTurtle f c l) states $ tail states+ let t = Turtle {+ field = f,+ input = (atomicModifyIORef_ index succ >>) . writeChan chan,+ info = \n -> fmap (n . (states !!)) $ readIORef index,+ shapes = shapesRef,+ inputs = fmap (flip take hist . pred) $ readIORef index,+ killTurtle = flushField f True $+ clearLayer l >> clearCharacter c >> killThread thr}+ shape t "classic" >> input t (Undonum 0) >> return t -killTurtle :: Turtle -> IO ()-killTurtle t = flushField (field t) True $ do- clearLayer $ layer t- clearCharacter $ character t- killThread $ thread t+runInputs :: Turtle -> [TurtleInput] -> IO ()+runInputs = mapM_ . input -input :: Turtle -> TurtleInput -> IO ()-input Turtle{inputChan = c, stateIndex = si} ti =- atomicModifyIORef_ si (+ 1) >>writeChan c ti+getSVG :: Turtle -> IO [SVG]+getSVG = fmap reverse . flip info drawed +convertPosition :: Turtle -> Position -> IO Position+convertPosition t p = do+ (w, h) <- windowSize t+ coord <- coordinates $ field t+ return $ case coord of+ CoordCenter -> S.center w h p+ CoordTopLeft -> S.topleft w h p+ -------------------------------------------------------------------------------- forward, backward :: Turtle -> Double -> IO ()@@ -171,15 +172,23 @@ backward t = forward t . negate goto :: Turtle -> Double -> Double -> IO ()-goto t x y = input t $ Goto x y+goto t@Turtle{field = f} x y = do+ coord <- coordinates f+ input t $ Goto $ case coord of+ CoordCenter -> Center x y+ CoordTopLeft -> TopLeft x y setx, sety :: Turtle -> Double -> IO () setx t x = do- (_, y) <- position t- input t $ Goto x y+ pos <- info t S.position >>= convertPosition t+ input t $ Goto $ case pos of+ Center _ y -> Center x y+ TopLeft _ y -> TopLeft x y sety t y = do- (x, _) <- position t- input t $ Goto x y+ pos <- info t S.position >>= convertPosition t+ input t $ Goto $ case pos of+ Center x _ -> Center x y+ TopLeft x _ -> TopLeft x y left, right, setheading :: Turtle -> Double -> IO () left t = input t . TurnLeft@@ -188,66 +197,70 @@ circle :: Turtle -> Double -> IO () circle t r = do- deg <- getDegrees t+ deg <- info t S.degrees forward t (r * pi / 36) left t (deg / 36) replicateM_ 35 $ forward t (2 * r * pi / 36) >> left t (deg / 36) forward t (r * pi / 36) input t $ Undonum 74 -write :: Turtle -> String -> Double -> String -> IO ()-write t fnt sz = input t . Write fnt sz+home :: Turtle -> IO ()+home t = goto t 0 0 >> setheading t 0 >> input t (Undonum 3) -stamp :: Turtle -> IO ()-stamp = (`input` Stamp)+undo :: Turtle -> IO ()+undo t = info t undonum >>= flip replicateM_ (input t Undo) +sleep :: Turtle -> Int -> IO ()+sleep t = input t . Sleep++flush :: Turtle -> IO ()+flush = (`input` Flush)++--------------------------------------------------------------------------------+ dot :: Turtle -> Double -> IO () dot t = input t . Dot +stamp :: Turtle -> IO ()+stamp = (`input` Stamp)++beginfill, endfill :: Turtle -> IO ()+beginfill = (`input` SetFill True)+endfill = (`input` SetFill False)++write :: Turtle -> String -> Double -> String -> IO ()+write t fnt sz = input t . Write fnt sz+ image :: Turtle -> FilePath -> Double -> Double -> IO ()-image t fp w h = input t $ PutImage fp w h+image t fp = curry $ input t . uncurry (PutImage fp) bgcolor :: ColorClass c => Turtle -> c -> IO () bgcolor t = input t . Bgcolor . getColor -home :: Turtle -> IO ()-home t = goto t 0 0 >> setheading t 0 >> input t (Undonum 3)- clear :: Turtle -> IO ()-clear t = input t Clear--undo :: Turtle -> IO ()-undo t = readIORef (stateIndex t)- >>= flip replicateM_ (input t Undo) . undonum . (states t !!)--sleep :: Turtle -> Int -> IO ()-sleep t = input t . Sleep--flushoff, flushon :: Turtle -> IO ()-flushoff = (`input` SetFlush False)-flushon = (`input` SetFlush True)--flush :: Turtle -> IO ()-flush = (`input` Flush)+clear = (`input` Clear) -------------------------------------------------------------------------------- addshape :: Turtle -> String -> [(Double, Double)] -> IO ()-addshape t n s = modifyIORef (shapes t) ((n, s) :)+addshape t n s = atomicModifyIORef_ (shapes t) ((n, s) :) +beginpoly :: Turtle -> IO ()+beginpoly = (`input` SetPoly True)++endpoly :: Turtle -> IO [(Double, Double)]+endpoly t = input t (SetPoly False) >> info t polyPoints >>=+ mapM (fmap (posX &&& posY) . convertPosition t)+ getshapes :: Turtle -> IO [String]-getshapes t = fmap (map fst) $ readIORef (shapes t)+getshapes = fmap (map fst) . readIORef . shapes shape :: Turtle -> String -> IO ()-shape t n = readIORef (shapes t) >>= input t . Shape . fromJust . lookup n+shape t n = readIORef (shapes t) >>=+ maybe (putStrLn $ "no shape named " ++ n) (input t . Shape) . lookup n shapesize :: Turtle -> Double -> Double -> IO ()-shapesize t sx sy = input t $ Shapesize sx sy--speed :: Turtle -> String -> IO ()-speed t str = case lookup str speedTable of- Just (ps, ds) -> input t (PositionStep ps) >> input t (DirectionStep ds)- Nothing -> putStrLn "no such speed"+shapesize t = curry $ input t . uncurry Shapesize hideturtle, showturtle :: Turtle -> IO () hideturtle = (`input` SetVisible False)@@ -257,79 +270,64 @@ penup = (`input` SetPendown False) pendown = (`input` SetPendown True) -beginfill, endfill :: Turtle -> IO ()-beginfill = (`input` SetFill True)-endfill = (`input` SetFill False)--beginpoly :: Turtle -> IO ()-beginpoly = (`input` SetPoly True)--endpoly :: Turtle -> IO [(Double, Double)]-endpoly t@Turtle{stateIndex = si, states = s} = do- input t $ SetPoly False- fmap (polyPoints . (s !!)) $ readIORef si- pencolor :: ColorClass c => Turtle -> c -> IO () pencolor t = input t . Pencolor . getColor pensize :: Turtle -> Double -> IO () pensize t = input t . Pensize +radians :: Turtle -> IO ()+radians = (`degrees` (2 * pi))+ degrees :: Turtle -> Double -> IO () degrees t = input t . Degrees -radians :: Turtle -> IO ()-radians = (`degrees` (2 * pi))+speed :: Turtle -> String -> IO ()+speed t str = case lookup str speedTable of+ Just (ps, ds) -> do+ input t $ PositionStep ps+ input t $ DirectionStep ds+ input t $ Undonum 3+ Nothing -> putStrLn "no such speed" +flushoff, flushon :: Turtle -> IO ()+flushoff = (`input` SetFlush False)+flushon = (`input` SetFlush True)+ -------------------------------------------------------------------------------- position :: Turtle -> IO (Double, Double)-position Turtle{stateIndex = si, states = s} =- fmap (S.position . (s !!)) $ readIORef si+position t = fmap (posX &&& posY) $ info t S.position >>= convertPosition t xcor, ycor :: Turtle -> IO Double xcor = fmap fst . position ycor = fmap snd . position +distance :: Turtle -> Double -> Double -> IO Double+distance t x0 y0 = do+ (x, y) <- position t+ return $ ((x - x0) ** 2 + (y - y0) ** 2) ** (1 / 2)+ heading :: Turtle -> IO Double-heading t@Turtle{stateIndex = si, states = s} = do- deg <- getDegrees t- dir <- fmap ((* (deg / (2 * pi))) . direction . (s !!)) $ readIORef si+heading t = do+ deg <- info t S.degrees+ dir <- fmap (* (deg / (2 * pi))) $ info t direction return $ dir `mod'` deg -getDegrees :: Turtle -> IO Double-getDegrees Turtle{stateIndex = si, states = s} =- fmap (S.degrees . (s !!)) $ readIORef si- towards :: Turtle -> Double -> Double -> IO Double towards t x0 y0 = do (x, y) <- position t- deg <- getDegrees t+ deg <- info t S.degrees let dir = atan2 (y0 - y) (x0 - x) * deg / (2 * pi) return $ if dir < 0 then dir + deg else dir -distance :: Turtle -> Double -> Double -> IO Double-distance t x0 y0 = do- (x, y) <- position t- return $ ((x - x0) ** 2 + (y - y0) ** 2) ** (1 / 2)- isdown, isvisible :: Turtle -> IO Bool-isdown t = fmap (S.pendown . (states t !!)) $ readIORef $ stateIndex t-isvisible t = fmap (visible . (states t !!)) $ readIORef $ stateIndex t+isdown = flip info S.pendown+isvisible = flip info visible windowWidth, windowHeight :: Turtle -> IO Double windowWidth = fmap fst . fieldSize . field windowHeight = fmap snd . fieldSize . field -----------------------------------------------------------------------------------getInputs :: Turtle -> IO [TurtleInput]-getInputs t = do- i <- readIORef $ stateIndex t- return $ take (i - 1) $ inputs t--sendInputs :: Turtle -> [TurtleInput] -> IO ()-sendInputs t = mapM_ (input t)--getSVG :: Turtle -> IO [SVG]-getSVG t = fmap (reverse . drawed . (states t !!)) $ readIORef $ stateIndex t+windowSize :: Turtle -> IO (Double, Double)+windowSize = fieldSize . field
src/Graphics/X11/Turtle/Data.hs view
@@ -11,7 +11,8 @@ ("turtle", unfold [ (- 10, 0), (- 8, 3), (- 10, 5), (- 7, 9), (- 5, 6), (0, 8), (4, 7), (6, 10), (8, 7), (7, 5), (10, 2), (13, 3), (16, 0)])]- where unfold = uncurry (++) . (id &&& (reverse . map (second negate)))+ where unfold = uncurry (++) .+ (id &&& reverse . map (second negate) . init . tail) speedTable :: [(String, (Maybe Double, Maybe Double))] speedTable = [
src/Graphics/X11/Turtle/Field.hs view
@@ -3,11 +3,15 @@ Field, Layer, Character,+ Coordinates(..), - -- * open and close+ -- * basic functions openField, closeField, waitField,+ topleft,+ center,+ coordinates, fieldSize, -- * draw@@ -18,8 +22,8 @@ -- ** to Layer addLayer, drawLine,- fillPolygon, fillRectangle,+ fillPolygon, writeString, drawImage, undoLayer,@@ -41,29 +45,28 @@ ) where import Graphics.X11.Turtle.XTools(- Display, Window, Pixmap, Atom, Point(..), Position, Dimension,+ Display, Window, Pixmap, Atom, Point(..), PositionXT, Dimension, XEventPtr, XIC, Bufs, undoBuf, bgBuf, topBuf, GCs, gcForeground, gcBackground, Event(..), forkIOX, openWindow, destroyWindow, closeDisplay, windowSize,- flush, colorPixel, setForeground, copyArea,- drawLineXT, writeStringXT,+ flush, copyArea, setForegroundXT,+ drawLineXT, fillRectangleXT, fillPolygonXT, writeStringXT, drawImageXT, allocaXEvent, waitEvent, pending, nextEvent, getEvent, filterEvent, utf8LookupString, buttonPress, buttonRelease, xK_VoidSymbol)-import qualified Graphics.X11.Turtle.XTools as X(fillPolygonXT, drawImageXT,- fillRectangle) import Graphics.X11.Turtle.Layers( Layers, Layer, Character, newLayers, redrawLayers,- makeLayer, addDraw, setBackground, undoLayer, clearLayer,- makeCharacter, setCharacter)-import Text.XML.YJSVG(Color(..))+ makeLayer, background, addDraw, undoLayer, clearLayer,+ makeCharacter, character)+import Text.XML.YJSVG(Position(..), Color(..)) -import Control.Monad(forever, replicateM, when, join, unless)+import Control.Monad(when, unless, forever, replicateM, join) import Control.Monad.Tools(doWhile_, doWhile, whenM) import Control.Arrow((***)) import Control.Concurrent(- forkIO, ThreadId, killThread, Chan, newChan, readChan, writeChan, threadDelay)--import Data.IORef(IORef, newIORef, readIORef, writeIORef, modifyIORef)+ 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.Convertible(convert) @@ -74,41 +77,48 @@ fIC :: XIC, fDel :: Atom, fSize :: IORef (Dimension, Dimension), fClick, fRelease :: IORef (Int -> Double -> Double -> IO Bool),- fDrag :: IORef (Double -> Double -> IO ()),- fMotion :: IORef (Double -> Double -> IO ()),- fKeypress :: IORef (Char -> IO Bool), fPressed :: IORef Bool,+ fDrag, fMotion :: IORef (Double -> Double -> IO ()),+ fKeypress :: IORef (Char -> IO Bool), fTimerEvent :: IORef (IO Bool),+ fPressed :: IORef Bool, - fLayers :: IORef Layers, fRunning :: IORef [ThreadId],- fLock, fClose, fEnd :: Chan (),- fInputChan :: Chan InputType- }+ fLayers :: IORef Layers, fInput :: Chan InputType,+ fCoordinates :: IORef Coordinates, fLock, fClose, fEnd :: Chan (),+ fRunning :: IORef [ThreadId]} makeField :: Display -> Window -> Bufs -> GCs -> XIC -> Atom -> IORef (Dimension, Dimension) -> IORef Layers -> IO Field makeField dpy win bufs gcs ic del sizeRef ls = do [click, release] <- replicateM 2 $ newIORef $ \_ _ _ -> return True- drag <- newIORef $ \_ _ -> return ()- motion <- newIORef $ \_ _ -> return ()+ [drag, motion] <- replicateM 2 $ newIORef $ \_ _ -> return () keypress <- newIORef $ \_ -> return True- pressed <- newIORef False timer <- newIORef $ return True- running <- newIORef []+ pressed <- newIORef False+ input <- newChan+ coord <- newIORef CoordCenter [lock, close, end] <- replicateM 3 newChan- inputChan <- newChan+ running <- newIORef [] writeChan lock () return Field{ fDisplay = dpy, fWindow = win, fBufs = bufs, fGCs = gcs, fIC = ic, fDel = del, fSize = sizeRef, - fClick = click, fRelease = release, fDrag = drag, fMotion = motion,- fKeypress = keypress, fPressed = pressed, fTimerEvent = timer,+ fClick = click, fRelease = release, fDrag = drag,+ fMotion = motion, fKeypress = keypress, fTimerEvent = timer,+ fPressed = pressed, - fLayers = ls,- fRunning = running,- fLock = lock, fClose = close, fEnd = end, fInputChan = inputChan- }+ fLayers = ls, fInput = input, fCoordinates = coord,+ fLock = lock, fClose = close, fEnd = end, fRunning = running} +data Coordinates = CoordCenter | CoordTopLeft++coordinates :: Field -> IO Coordinates+coordinates = readIORef . fCoordinates++topleft, center :: Field -> IO ()+topleft = flip (writeIORef . fCoordinates) CoordTopLeft+center = flip (writeIORef . fCoordinates) CoordCenter+ -------------------------------------------------------------------------------- openField :: IO Field@@ -117,9 +127,10 @@ let (ub, bb, tb) = (undoBuf bufs, bgBuf bufs, topBuf bufs) (gcf, gcb) = (gcForeground gcs, gcBackground gcs) sizeRef <- newIORef size- let getSize = readIORef sizeRef+ let getSize = readIORef sizeRef ls <- newLayers 50 - (getSize >>= uncurry (X.fillRectangle dpy ub gcb 0 0))+ (setForegroundXT dpy gcb (RGB 255 255 255) >>+ getSize >>= uncurry (fillRectangleXT dpy ub gcb 0 0)) (getSize >>= \(w, h) -> copyArea dpy ub bb gcf 0 0 w h 0 0) (getSize >>= \(w, h) -> copyArea dpy bb tb gcf 0 0 w h 0 0) f <- makeField dpy win bufs gcs ic del sizeRef ls@@ -129,48 +140,42 @@ data InputType = XInput | End | Timer -waitInput :: Field -> IO (Chan InputType, Chan ())+waitInput :: Field -> IO (Chan ()) waitInput f = do--- go <- newChan- let go = fInputChan f empty <- newChan tid <- forkIOX $ forever $ do waitEvent $ fDisplay f- writeChan go XInput+ writeChan (fInput f) XInput readChan empty- modifyIORef (fRunning f) (tid :)+ atomicModifyIORef_ (fRunning f) (tid :) _ <- forkIO $ do readChan $ fClose f killThread tid- writeChan go End- return (go, empty)+ writeChan (fInput f) End+ return empty runLoop :: Field -> IO () runLoop f = allocaXEvent $ \e -> do- (go, empty) <- waitInput f+ empty <- waitInput f doWhile_ $ do- iType <- readChan go- cont' <- case iType of+ iType <- readChan $ fInput f+ cont <- case iType of+ End -> return False Timer -> do c <- join $ readIORef $ fTimerEvent f- unless c $ readIORef (fRunning f) >>= mapM_ killThread- return c -- readIORef (fTimerEvent f) >>= k- _ -> return True- let notEnd = case iType of- End -> False- _ -> True- cont <- doWhile True $ const $ do- evN <- pending $ fDisplay f- if evN > 0 then do+ unless c $ readIORef (fRunning f)+ >>= mapM_ killThread+ return c+ XInput -> doWhile undefined $ const $ do+ evN <- pending $ fDisplay f+ if evN <= 0 then return (True, False) else do nextEvent (fDisplay f) e filtered <- filterEvent e 0 if filtered then return (True, True) else do ev <- getEvent e c <- processEvent f e ev return (c, c)- else return (True, False)- if notEnd && cont && cont' then writeChan empty () >> return True- else return False+ if cont then writeChan empty () >> return True else return False readIORef (fRunning f) >>= mapM_ killThread destroyWindow (fDisplay f) (fWindow f) closeDisplay $ fDisplay f@@ -180,15 +185,18 @@ processEvent f e ev = case ev of ExposeEvent{} -> flushField f True $ do windowSize (fDisplay f) (fWindow f) >>= writeIORef (fSize f)- redrawLayers $ fLayers f- return True+ redrawLayers (fLayers f) >> return True KeyEvent{} -> do (mstr, mks) <- utf8LookupString (fIC f) e let str = fromMaybe "" mstr _ks = fromMaybe xK_VoidSymbol mks readIORef (fKeypress f) >>= fmap and . ($ str) . mapM ButtonEvent{} -> do- pos <- center (ev_x ev) (ev_y ev)+ coord <- readIORef $ fCoordinates f+ pos <- case coord of+ CoordCenter -> cntr (ev_x ev) (ev_y ev)+ CoordTopLeft -> return+ (fromIntegral $ ev_x ev, fromIntegral $ ev_y ev) let buttonN = fromIntegral $ ev_button ev case ev_event_type ev of et | et == buttonPress -> do@@ -201,7 +209,7 @@ ($ pos) . uncurry . ($ buttonN) _ -> error "not implement event" MotionEvent{} -> do- pos <- center (ev_x ev) (ev_y ev)+ pos <- cntr (ev_x ev) (ev_y ev) whenM (readIORef $ fPressed f) $ readIORef (fDrag f) >>= ($ pos) . uncurry readIORef (fMotion f) >>= ($ pos) . uncurry@@ -209,7 +217,7 @@ ClientMessageEvent{} -> return $ convert (head $ ev_data ev) /= fDel f _ -> return True where- center x y = do+ cntr x y = do (w, h) <- fieldSize f return (fromIntegral x - w / 2, fromIntegral (- y) + h / 2) @@ -227,27 +235,22 @@ forkField :: Field -> IO () -> IO ThreadId forkField f act = do tid <- forkIOX act- modifyIORef (fRunning f) (tid :)- return tid+ atomicModifyIORef_ (fRunning f) (tid :) >> return tid flushField :: Field -> Bool -> IO a -> IO a flushField f real act = do- readChan $ fLock f- ret <- act+ ret <- readChan (fLock f) >> act when real $ do (w, h) <- readIORef $ fSize f copyArea (fDisplay f) (topBuf $ fBufs f) (fWindow f) (gcForeground $ fGCs f) 0 0 w h 0 0 flush $ fDisplay f- writeChan (fLock f) ()- return ret+ writeChan (fLock f) () >> return ret fieldColor :: Field -> Layer -> Color -> IO ()-fieldColor f l c = setBackground l $ do- colorPixel (fDisplay f) c >>=- maybe (return ())- (setForeground (fDisplay f) (gcBackground $ fGCs f))- readIORef (fSize f) >>= uncurry (X.fillRectangle+fieldColor f l clr = background l $ do+ setForegroundXT (fDisplay f) (gcBackground $ fGCs f) clr+ readIORef (fSize f) >>= uncurry (fillRectangleXT (fDisplay f) (undoBuf $ fBufs f) (gcBackground $ fGCs f) 0 0) --------------------------------------------------------------------------------@@ -255,88 +258,79 @@ addLayer :: Field -> IO Layer addLayer = makeLayer . fLayers -drawLine :: Field -> Layer -> Double -> Color ->- Double -> Double -> Double -> Double -> IO ()-drawLine f l lw clr x1 y1 x2 y2 =- addDraw l (drawLineBuf f undoBuf (round lw) clr x1 y1 x2 y2,- drawLineBuf f bgBuf (round lw) clr x1 y1 x2 y2)+drawLayer :: Field -> Layer -> (Pixmap -> IO ()) -> IO ()+drawLayer Field{fBufs = bufs} l draw =+ addDraw l (draw $ undoBuf bufs, draw $ bgBuf bufs) -writeString :: Field -> Layer -> String -> Double -> Color ->- Double -> Double -> String -> IO ()-writeString f l fname size clr xc yc str = addDraw l (ws undoBuf, ws bgBuf)- where ws bf = do- (x, y) <- topLeft f xc yc- writeStringXT (fDisplay f) (bf $ fBufs f) fname size clr x y str+drawLine :: Field -> Layer -> Double -> Color -> Position -> Position -> IO ()+drawLine f l lw clr p1 p2 =+ drawLayer f l $ \buf -> drawLineBuf f buf (round lw) clr p1 p2 -drawImage :: Field -> Layer -> FilePath -> Double -> Double -> Double -> Double -> IO ()-drawImage f l fp xc yc w h = addDraw l (di undoBuf, di bgBuf)- where di bf = do- (x, y) <- topLeft f xc yc- X.drawImageXT (fDisplay f) (bf $ fBufs f) (gcForeground $ fGCs f)- fp x y (round w) (round h)+writeString :: Field -> Layer -> String -> Double -> Color -> Position ->+ String -> IO ()+writeString f@Field{fDisplay = dpy} l fname size clr pos str =+ drawLayer f l $ \buf -> getPosition f pos >>=+ flip (uncurry $ writeStringXT dpy buf fname size clr) str -fillPolygon :: Field -> Layer -> [(Double, Double)] -> Color -> IO ()-fillPolygon f l psc clr = addDraw l (fp undoBuf, fp bgBuf)- where fp bf = do- ps <- mapM (fmap (uncurry Point) . uncurry (topLeft f)) psc- colorPixel (fDisplay f) clr >>= maybe (return ())- (setForeground (fDisplay f) (gcForeground $ fGCs f))- X.fillPolygonXT (fDisplay f) (bf $ fBufs f) (gcForeground $ fGCs f) ps+drawImage :: Field -> Layer -> FilePath -> Position -> Double -> Double -> IO ()+drawImage f@Field{fDisplay = dpy} l fp pos w h = drawLayer f l $ \buf -> do+ (x, y) <- getPosition f pos+ drawImageXT dpy buf (gcForeground $ fGCs f) fp x y (round w) (round h) -fillRectangle ::- Field -> Layer -> Double -> Double -> Double -> Double -> Color -> IO ()-fillRectangle f l xc0 yc0 w h clr = addDraw l (fr undoBuf, fr bgBuf)- where fr bf = do- (x0, y0) <- topLeft f xc0 yc0- colorPixel (fDisplay f) clr >>= maybe (return ())- (setForeground (fDisplay f) (gcForeground $ fGCs f))- X.fillRectangle (fDisplay f) (bf $ fBufs f) (gcForeground $ fGCs f)- x0 y0 (round w) (round h)+fillPolygon :: Field -> Layer -> [Position] -> Color -> IO ()+fillPolygon f@Field{fDisplay = dpy} l positions clr = drawLayer f l $ \buf -> do+ ps <- mapM (fmap (uncurry Point) . getPosition f) positions+ setForegroundXT dpy (gcForeground $ fGCs f) clr+ fillPolygonXT dpy buf (gcForeground $ fGCs f) ps -drawLineBuf :: Field -> (Bufs -> Pixmap) -> Int -> Color ->- Double -> Double -> Double -> Double -> IO ()-drawLineBuf f bf lw c x1_ y1_ x2_ y2_ = do- (x1, y1) <- topLeft f x1_ y1_- (x2, y2) <- topLeft f x2_ y2_- drawLineXT (fDisplay f) (gcForeground $ fGCs f) (bf $ fBufs f) lw c- x1 y1 x2 y2+fillRectangle :: Field -> Layer -> Position -> Double -> Double -> Color -> IO ()+fillRectangle f@Field{fDisplay = dpy} l p w h clr = drawLayer f l $ \buf -> do+ (x, y) <- getPosition f p+ setForegroundXT dpy (gcForeground $ fGCs f) clr+ fillRectangleXT dpy buf (gcForeground $ fGCs f) x y (round w) (round h) -topLeft :: Field -> Double -> Double -> IO (Position, Position)-topLeft f x y = do- (width, height) <- fieldSize f- return (round $ x + width / 2, round $ - y + height / 2)+drawLineBuf :: Field -> Pixmap -> Int -> Color -> Position -> Position -> IO ()+drawLineBuf f@Field{fDisplay = dpy} buf lw clr p1 p2 = do+ (x1, y1) <- getPosition f p1+ (x2, y2) <- getPosition f p2+ drawLineXT dpy (gcForeground $ fGCs f) buf lw clr x1 y1 x2 y2 +getPosition :: Field -> Position -> IO (PositionXT, PositionXT)+getPosition f (Center x y) = do+ (w, h) <- fieldSize f+ return (round x + round (w / 2), - round y + round (h / 2))+getPosition _ (TopLeft x y) = return (round x, round y)+ -------------------------------------------------------------------------------- addCharacter :: Field -> IO Character addCharacter = makeCharacter . fLayers -drawCharacter :: Field -> Character -> Color -> [(Double, Double)] -> IO ()-drawCharacter f c clr sh = setCharacter c $ drawShape f clr sh+drawCharacter :: Field -> Character -> Color -> [Position] -> IO ()+drawCharacter f c clr sh = character c $ drawShape f clr sh -drawCharacterAndLine :: Field -> Character -> Color -> [(Double, Double)] ->- Double -> Double -> Double -> Double -> Double -> IO ()-drawCharacterAndLine f c clr sh lw x1 y1 x2 y2 = setCharacter c $- drawShape f clr sh >> drawLineBuf f topBuf (round lw) clr x1 y1 x2 y2+drawCharacterAndLine :: Field -> Character -> Color -> [Position] ->+ Double -> Position -> Position -> IO ()+drawCharacterAndLine f c clr sh lw p1 p2 = character c $ do+ drawShape f clr sh+ drawLineBuf f (topBuf $ fBufs f) (round lw) clr p1 p2 -drawShape :: Field -> Color -> [(Double, Double)] -> IO ()-drawShape f clr psc = do- ps <- mapM (fmap (uncurry Point) . uncurry (topLeft f)) psc- colorPixel (fDisplay f) clr >>= maybe (return ())- (setForeground (fDisplay f) (gcForeground $ fGCs f))- X.fillPolygonXT (fDisplay f) (topBuf $ fBufs f) (gcForeground $ fGCs f) ps+drawShape :: Field -> Color -> [Position] -> IO ()+drawShape f clr positions = do+ ps <- mapM (fmap (uncurry Point) . getPosition f) positions+ setForegroundXT (fDisplay f) (gcForeground $ fGCs f) clr+ fillPolygonXT (fDisplay f) (topBuf $ fBufs f) (gcForeground $ fGCs f) ps clearCharacter :: Character -> IO ()-clearCharacter c = setCharacter c $ return ()+clearCharacter c = character c $ return () -------------------------------------------------------------------------------- onclick, onrelease :: Field -> (Int -> Double -> Double -> IO Bool) -> IO ()-(onclick, onrelease) = (writeIORef .) *** (writeIORef .) $ (fClick, fRelease)+(onclick, onrelease) = (writeIORef . fClick, writeIORef . fRelease) ondrag, onmotion :: Field -> (Double -> Double -> IO ()) -> IO ()-ondrag = writeIORef . fDrag-onmotion = writeIORef . fMotion+(ondrag, onmotion) = (writeIORef . fDrag, writeIORef . fMotion) onkeypress :: Field -> (Char -> IO Bool) -> IO () onkeypress = writeIORef . fKeypress@@ -345,4 +339,4 @@ ontimer f t fun = do writeIORef (fTimerEvent f) fun threadDelay $ t * 1000- writeChan (fInputChan f) Timer+ writeChan (fInput f) Timer
src/Graphics/X11/Turtle/Input.hs view
@@ -17,41 +17,39 @@ polyPoints ) where -import Graphics.X11.Turtle.State(TurtleState(..), initialTurtleState)+import Graphics.X11.Turtle.State(TurtleState(..), initialTurtleState, makeShape) import Text.XML.YJSVG(SVG(..), Color(..), Position(..))- import Control.Concurrent.Chan(Chan, newChan, getChanContents)-import Control.Arrow -------------------------------------------------------------------------------- data TurtleInput- = Shape [(Double, Double)]- | Shapesize Double Double- | Pencolor Color- | Pensize Double- | SetPendown Bool- | SetFill Bool- | SetPoly Bool- | SetVisible Bool- | Degrees Double- | PositionStep (Maybe Double)- | DirectionStep (Maybe Double)- | Undonum Int- | Goto Double Double+ = Goto Position+ | Forward Double | Rotate Double+ | TurnLeft Double+ | Dot Double+ | Stamp | Write String Double String | PutImage FilePath Double Double- | Stamp- | Dot Double- | Bgcolor Color | Undo+ | Undonum Int | Clear- | Forward Double- | TurnLeft Double | Sleep Int- | SetFlush Bool | Flush+ | Shape [(Double, Double)]+ | Shapesize Double Double+ | Pensize Double+ | Pencolor Color+ | Bgcolor Color+ | SetPendown Bool+ | SetVisible Bool+ | SetFill Bool+ | SetPoly Bool+ | SetFlush Bool+ | PositionStep (Maybe Double)+ | DirectionStep (Maybe Double)+ | Degrees Double deriving (Show, Read) turtleSeries :: IO (Chan TurtleInput, [TurtleInput], [TurtleState])@@ -65,78 +63,61 @@ inputToTurtle [] ts0 (Undo : tis) = ts0 : inputToTurtle [] ts0 tis inputToTurtle (tsb : tsbs) _ (Undo : tis) = let ts1 = tsb{undo = True} in ts1 : inputToTurtle tsbs ts1 tis-inputToTurtle tsbs ts0 (Forward len : tis) = let- (x0, y0) = position ts0- x = x0 + len * cos (direction ts0)- y = y0 + len * sin (direction ts0) in- inputToTurtle tsbs ts0 $ Goto x y : tis+inputToTurtle tsbs ts0 (Forward len : tis) = case position ts0 of+ Center x0 y0 -> let+ x = x0 + len * cos (direction ts0)+ y = y0 + len * sin (direction ts0) in+ inputToTurtle tsbs ts0 $ Goto (Center x y) : tis+ TopLeft x0 y0 -> let+ x = x0 + len * cos (direction ts0)+ y = y0 - len * sin (direction ts0) in+ inputToTurtle tsbs ts0 $ Goto (TopLeft x y) : tis inputToTurtle tsbs ts0 (TurnLeft dd : tis) = inputToTurtle tsbs ts0 $ Rotate (direction ts0 * degrees ts0 / (2 * pi) + dd) : tis inputToTurtle tsbs ts0 (ti : tis) = let ts1 = nextTurtle ts0 ti in ts1 : inputToTurtle (ts0 : tsbs) ts1 tis inputToTurtle _ _ [] = error "no more input" +reset :: TurtleState -> TurtleState+reset t = t{draw = Nothing, clear = False, undo = False, undonum = 1,+ sleep = Nothing, flush = False}++set :: TurtleState -> Maybe SVG -> TurtleState+set t drw = t{draw = drw, drawed = maybe id (:) drw $ drawed t}+ nextTurtle :: TurtleState -> TurtleInput -> TurtleState-nextTurtle t (Shape sh) = (clearState t){shape = sh}-nextTurtle t (Shapesize sx sy) = (clearState t){shapesize = (sx, sy)}-nextTurtle t (Pencolor c) = (clearState t){pencolor = c}-nextTurtle t (Pensize ps) = (clearState t){pensize = ps}-nextTurtle t (SetPendown pd) = (clearState t){pendown = pd}-nextTurtle t (SetFill f) = (clearState t){- fill = f,- draw = if fill t && not f then Just fl else Nothing,- drawed = if fill t && not f then fl : drawed t else drawed t,- fillPoints = [(x0, y0) | f]}- where- (x0, y0) = position t- fl = Polyline (uncurry Center `map` fillPoints t)- (pencolor t) (pencolor t) 0-nextTurtle t (SetPoly p) = (clearState t){- poly = p,- polyPoints = if p then [position t] else polyPoints t}-nextTurtle t (SetVisible v) = (clearState t){visible = v}-nextTurtle t (Degrees ds) = (clearState t){degrees = ds}-nextTurtle t (PositionStep ps) = (clearState t){positionStep = ps}-nextTurtle t (DirectionStep ds) = (clearState t){directionStep = ds}-nextTurtle t (Undonum un) = (clearState t){undonum = un}-nextTurtle t (Goto x y) = (clearState t){- position = (x, y),- draw = if pendown t then Just ln else Nothing,- drawed = if pendown t then ln : drawed t else drawed t,- fillPoints = if fill t then (x, y) : fillPoints t else fillPoints t,- polyPoints = if poly t then (x, y) : polyPoints t else polyPoints t}- where- (x0, y0) = position t- ln = Line (Center x0 y0) (Center x y) (pencolor t) (pensize t)-nextTurtle t (Rotate d) = (clearState t){direction = d * 2 * pi / degrees t}-nextTurtle t (Write fnt sz str) = (clearState t){- draw = Just txt, drawed = txt : drawed t}- where txt = Text (uncurry Center $ position t) sz (pencolor t) fnt str-nextTurtle t (PutImage fp w h) = (clearState t){- draw = Just img, drawed = img : drawed t}- where img = Image (uncurry Center $ position t) w h fp-nextTurtle t Stamp = (clearState t){- draw = Just stamp, drawed = stamp : drawed t}- where- (x0, y0) = position t- sp = let (sx, sy) = shapesize t in- map (((+ x0) *** (+ y0)) . rotate . ((* sx) *** (* sy))) $ shape t- rotate (x, y) = let rad = direction t in- (x * cos rad - y * sin rad, x * sin rad + y * cos rad)- points = map (uncurry Center) sp- stamp = Polyline points (pencolor t) (pencolor t) 0-nextTurtle t (Dot sz) = (clearState t){- draw = Just dot, drawed = dot : drawed t}- where- dot = Rect (uncurry Center $ position t) sz sz 0 (pencolor t) (pencolor t)-nextTurtle t (Bgcolor c) = (clearState t){- bgcolor = c, drawed = init (drawed t) ++ [Fill c]}-nextTurtle t Clear = (clearState t){clear = True, drawed = [last $ drawed t]}-nextTurtle t (Sleep time) = (clearState t){sleep = Just time}-nextTurtle t (SetFlush ss) = (clearState t){stepbystep = ss}-nextTurtle t Flush = (clearState t){flush = True}+nextTurtle t (Goto pos) = (reset t){position = pos,+ fillPoints = (if fill t then (pos :) else id) $ fillPoints t,+ polyPoints = (if poly t then (pos :) else id) $ polyPoints t}+ `set` if not $ pendown t then Nothing+ else Just $ Line pos (position t) (pencolor t) (pensize t)+nextTurtle t (Rotate dir) = (reset t){direction = dir * 2 * pi / degrees t}+nextTurtle t (Dot sz) =+ reset t `set` Just (Rect (position t) sz sz 0 (pencolor t) (pencolor t))+nextTurtle t@TurtleState{pencolor = clr} Stamp = reset t `set`+ Just (Polyline (makeShape t (direction t) (position t)) clr clr 0)+nextTurtle t (Write fnt sz str) =+ reset t `set` Just (Text (position t) sz (pencolor t) fnt str)+nextTurtle t (PutImage fp w h) = reset t `set` Just (Image (position t) w h fp)+nextTurtle t (Undonum un) = (reset t){undonum = un}+nextTurtle t Clear = (reset t){clear = True, drawed = [last $ drawed t]}+nextTurtle t (Sleep time) = (reset t){sleep = Just time}+nextTurtle t Flush = (reset t){flush = True}+nextTurtle t (Shape sh) = (reset t){shape = sh}+nextTurtle t (Shapesize sx sy) = (reset t){shapesize = (sx, sy)}+nextTurtle t (Pensize ps) = (reset t){pensize = ps}+nextTurtle t (Pencolor clr) = (reset t){pencolor = clr}+nextTurtle t (Bgcolor clr) = (reset t){+ draw = Just $ Fill clr, drawed = init (drawed t) ++ [Fill clr]}+nextTurtle t (SetPendown pd) = (reset t){pendown = pd}+nextTurtle t (SetVisible v) = (reset t){visible = v}+nextTurtle t (SetFill fl) = (reset t){fill = fl, fillPoints = [position t | fl]}+ `set` (if not (fill t) || fl then Nothing+ else Just $ Polyline (fillPoints t) (pencolor t) (pencolor t) 0)+nextTurtle t (SetPoly p) = (reset t){+ poly = p, polyPoints = if p then [position t] else polyPoints t}+nextTurtle t (SetFlush ss) = (reset t){stepbystep = ss}+nextTurtle t (PositionStep ps) = (reset t){positionStep = ps}+nextTurtle t (DirectionStep ds) = (reset t){directionStep = ds}+nextTurtle t (Degrees ds) = (reset t){degrees = ds} nextTurtle _ _ = error "not defined"--clearState :: TurtleState -> TurtleState-clearState t = t{undonum = 1, undo = False, clear = False, draw = Nothing,- sleep = Nothing, flush = False}
src/Graphics/X11/Turtle/Layers.hs view
@@ -11,11 +11,11 @@ -- * draws redrawLayers,+ background, addDraw,- setBackground, undoLayer, clearLayer,- setCharacter+ character ) where import Control.Monad(when, unless)@@ -26,15 +26,14 @@ -------------------------------------------------------------------------------- data Layers = Layers{- undoNum :: Int,- clearLayersAction :: IO (),- undoLayersAction :: IO (),- clearCharactersAction :: IO (),- background :: [IO ()],- buffed :: [IO ()],+ backgrounds :: [IO ()],+ buffers :: [IO ()], layers :: [[(IO (), IO ())]],- characters :: [IO ()]- }+ characters :: [IO ()],+ buffSize :: Int,+ clearBuffers :: IO (),+ clearLayers :: IO (),+ clearCharacters :: IO ()} data Layer = Layer{ layerId :: Int,@@ -49,22 +48,21 @@ -------------------------------------------------------------------------------- newLayers :: Int -> IO () -> IO () -> IO () -> IO (IORef Layers)-newLayers un cla ula cca = newIORef Layers{- undoNum = un,- clearLayersAction = cla,- undoLayersAction = ula,- clearCharactersAction = cca,- background = [],- buffed = [],+newLayers bsize cbuf clyr cchr = newIORef Layers{+ backgrounds = [],+ buffers = [], layers = [],- characters = []- }+ characters = [],+ buffSize = bsize,+ clearBuffers = cbuf,+ clearLayers = clyr,+ clearCharacters = cchr} makeLayer :: IORef Layers -> IO Layer makeLayer rls = atomicModifyIORef rls $ \ls -> (ls{- layers = layers ls ++ [[]],- buffed = buffed ls ++ [return ()],- background = background ls ++[return ()]},+ backgrounds = backgrounds ls ++[return ()],+ buffers = buffers ls ++ [return ()],+ layers = layers ls ++ [[]]}, Layer{layerId = length $ layers ls, layerLayers = rls}) makeCharacter :: IORef Layers -> IO Character@@ -77,27 +75,27 @@ redrawLayers :: IORef Layers -> IO () redrawLayers rls = readIORef rls >>= \ls -> do- sequence_ $ background ls- clearLayersAction ls >> sequence_ (buffed ls)- undoLayersAction ls >> mapM_ snd (concat $ layers ls)- clearCharactersAction ls >> sequence_ (characters ls)+ clearBuffers ls >> sequence_ (backgrounds ls) >> sequence_ (buffers ls)+ clearLayers ls >> mapM_ snd (concat $ layers ls)+ clearCharacters ls >> sequence_ (characters ls) addDraw :: Layer -> (IO (), IO ()) -> IO () addDraw Layer{layerId = lid, layerLayers = rls} acts@(_, act) = do readIORef rls >>= \ls -> do- act >> clearCharactersAction ls >> sequence_ (characters ls)- unless (length (layers ls !! lid) < undoNum ls) $+ act >> clearCharacters ls >> sequence_ (characters ls)+ unless (length (layers ls !! lid) < buffSize ls) $ fst $ head $ layers ls !! lid- atomicModifyIORef_ rls $ \ls -> if length (layers ls !! lid) < undoNum ls- then ls{layers = modifyAt (layers ls) lid (++ [acts])}- else let (a, _) : as = layers ls !! lid in ls{- layers = setAt (layers ls) lid $ as ++ [acts],- buffed = modifyAt (buffed ls) lid (>> a)}+ atomicModifyIORef_ rls $ \ls ->+ if length (layers ls !! lid) < buffSize ls+ then ls{layers = modifyAt (layers ls) lid (++ [acts])}+ else let (a, _) : as = layers ls !! lid in ls{+ layers = setAt (layers ls) lid $ as ++ [acts],+ buffers = modifyAt (buffers ls) lid (>> a)} -setBackground :: Layer -> IO () -> IO ()-setBackground Layer{layerId = lid, layerLayers = rls} act = do+background :: Layer -> IO () -> IO ()+background Layer{layerId = lid, layerLayers = rls} act = do atomicModifyIORef_ rls $ \ls ->- ls{background = setAt (background ls) lid act}+ ls{backgrounds = setAt (backgrounds ls) lid act} redrawLayers rls undoLayer :: Layer -> IO Bool@@ -106,20 +104,21 @@ then (ls, False) else (ls{layers = modifyAt (layers ls) lid init}, True) when done $ readIORef rls >>= \ls -> do- undoLayersAction ls >> mapM_ snd (concat $ layers ls)- clearCharactersAction ls >> sequence_ (characters ls)+ clearLayers ls >> mapM_ snd (concat $ layers ls)+ clearCharacters ls >> sequence_ (characters ls) return done clearLayer :: Layer -> IO () clearLayer Layer{layerId = lid, layerLayers = rls} = do atomicModifyIORef_ rls $ \ls -> ls{- layers = setAt (layers ls) lid [],- buffed = setAt (buffed ls) lid $ return ()}+ backgrounds = setAt (backgrounds ls) lid $ return (),+ buffers = setAt (buffers ls) lid $ return (),+ layers = setAt (layers ls) lid []} redrawLayers rls -setCharacter :: Character -> IO () -> IO ()-setCharacter Character{characterId = cid, characterLayers = rls} act = do+character :: Character -> IO () -> IO ()+character Character{characterId = cid, characterLayers = rls} act = do atomicModifyIORef_ rls $ \ls -> ls{characters = setAt (characters ls) cid act} readIORef rls >>= \ls ->- clearCharactersAction ls >> sequence_ (characters ls)+ clearCharacters ls >> sequence_ (characters ls)
src/Graphics/X11/Turtle/Move.hs view
@@ -1,23 +1,25 @@-module Graphics.X11.Turtle.Move (+module Graphics.X11.Turtle.Move( -- * types Field,- Layer,- Character,+ Coordinates(..), -- * process Field openField, closeField,- forkField,- waitField, fieldSize,+ coordinates,+ topleft,+ center,+ waitField, -- * draws+ forkField, flushField,- moveTurtle, addLayer, clearLayer, addCharacter, clearCharacter,+ moveTurtle, -- * event onclick,@@ -28,21 +30,21 @@ ontimer ) where -import Graphics.X11.Turtle.State(TurtleState(..))+import Graphics.X11.Turtle.State(TurtleState(..), makeShape) import Graphics.X11.Turtle.Field(- Field, Layer, Character,- openField, closeField, waitField, fieldSize,- forkField, flushField, fieldColor,- addLayer, drawLine, writeString, undoLayer, clearLayer, fillPolygon,- fillRectangle,- addCharacter, drawCharacter, drawCharacterAndLine, clearCharacter,- onclick, onrelease, ondrag, onmotion, onkeypress, drawImage, ontimer)+ Field, Layer, Character, Coordinates(..),+ openField, closeField, fieldSize, coordinates, topleft, center,+ waitField, forkField, flushField,+ addLayer, clearLayer, addCharacter, clearCharacter,+ onclick, onrelease, ondrag, onmotion, onkeypress, ontimer,+ fieldColor, drawLine, fillRectangle, fillPolygon, writeString,+ drawImage, undoLayer, drawCharacter, drawCharacterAndLine) import Text.XML.YJSVG(SVG(..), Position(..))+import qualified Text.XML.YJSVG as S(topleft) import Control.Concurrent(threadDelay) import Control.Monad(when, unless, forM_) import Control.Monad.Tools(unlessM)-import Control.Arrow((***)) import Data.Maybe(isJust) --------------------------------------------------------------------------------@@ -51,70 +53,64 @@ moveTurtle _ _ _ _ TurtleState{sleep = Just t} = threadDelay $ 1000 * t moveTurtle f _ _ _ TurtleState{flush = True} = flushField f True $ return () moveTurtle f c l t0 t1 = do- when (undo t1) $ flushField f fl $ do+ (w, h) <- fieldSize f+ when (undo t1) $ fl $ do when (clear t0) redraw when (isJust $ draw t0) $ do unlessM (undoLayer l) $ clearLayer l >> redraw- when (visible t1) $ drawT (direction t1) $ position t0+ when (visible t1) $ drawTtl (direction t0) $ position t0 when (visible t1) $ do- forM_ (directions t0 t1) $ \dir -> flushField f fl $- drawT dir (position t0) >> threadDelay (interval t0)- forM_ (positions t0 t1) $ \p -> flushField f fl $- drawT (direction t1) p >> threadDelay (interval t0)- flushField f fl $ drawT (direction t1) $ position t1- when (bgcolor t0 /= bgcolor t1) $- flushField f fl $ fieldColor f l $ bgcolor t1- unless (undo t1) $ flushField f fl $ do- when (visible t0 && not (visible t1)) $ clearCharacter c- when (clear t1) $ clearLayer l- maybe (return ()) (drawSVG f l) (draw t1)+ forM_ (directions t0 t1) $ \dir -> fl $+ drawTtl dir (position t0) >> threadDelay (interval t0)+ forM_ (positions w h t0 t1) $ \p -> fl $+ drawTtl (direction t1) p >> threadDelay (interval t0)+ fl $ drawTtl (direction t1) $ position t1+ when (visible t0 && not (visible t1)) $ fl $ clearCharacter c+ when (clear t1) $ fl $ clearLayer l+ unless (undo t1) $ fl $ maybe (return ()) (drawSVG f l) (draw t1) where- fl = stepbystep t0+ fl = flushField f $ stepbystep t0 redraw = mapM_ (drawSVG f l) $ reverse $ drawed t1- drawT d p = drawTurtle f c t1 d p lineOrigin- lineOrigin | undo t1 && pendown t0 = Just $ position t1- | pendown t1 = Just $ position t0- | otherwise = Nothing+ drawTtl dir pos = drawTurtle f c t1 dir pos begin+ begin | undo t1 && pendown t0 = Just $ position t1+ | pendown t1 = Just $ position t0+ | otherwise = Nothing drawSVG :: Field -> Layer -> SVG -> IO ()-drawSVG f l (Line (Center x0 y0) (Center x1 y1) clr lw) =- drawLine f l lw clr x0 y0 x1 y1-drawSVG f l (Text (Center x y) sz clr fnt str) =- writeString f l fnt sz clr x y str-drawSVG f l (Polyline ps fc _ 0) = fillPolygon f l (map posToTup ps) fc- where- posToTup (Center x y) = (x, y)- posToTup _ = error "not implemented"-drawSVG f l (Rect (Center x y) w h 0 fc _) = fillRectangle f l x y w h fc-drawSVG f l (Image (Center x0 y0) w h fp) = drawImage f l fp x0 y0 w h-drawSVG _ _ (Fill _) = return ()+drawSVG f l (Line p0 p1 clr lw) = drawLine f l lw clr p0 p1+drawSVG f l (Rect pos w h 0 fc _) = fillRectangle f l pos w h fc+drawSVG f l (Polyline ps fc _ 0) = fillPolygon f l ps fc+drawSVG f l (Fill clr) = fieldColor f l clr+drawSVG f l (Text pos sz clr fnt str) = writeString f l fnt sz clr pos str+drawSVG f l (Image pos w h fp) = drawImage f l fp pos w h drawSVG _ _ _ = error "not implemented" -positions :: TurtleState -> TurtleState -> [(Double, Double)]-positions t0 t1 = case positionStep t0 of- Nothing -> []- Just step -> take (floor $ dist / step) $ zip- [x0, x0 + step * (x1 - x0) / dist .. ]- [y0, y0 + step * (y1 - y0) / dist .. ]+positions :: Double -> Double -> TurtleState -> TurtleState -> [Position]+positions w h t0 t1 =+ maybe [] (mkPositions w h (position t0) (position t1)) $ positionStep t0++mkPositions :: Double -> Double -> Position -> Position -> Double -> [Position]+mkPositions w h p1 p2 step = case (p1, p2) of+ (Center x0 y0, Center x1 y1) -> map (uncurry Center) $ mp x0 y0 x1 y1+ (TopLeft x0 y0, TopLeft x1 y1) -> map (uncurry TopLeft) $ mp x0 y0 x1 y1+ _ -> mkPositions w h (S.topleft w h p1) (S.topleft w h p2) step where- [(x0, y0), (x1, y1)] = map position [t0, t1]- dist = ((x1 - x0) ** 2 + (y1 - y0) ** 2) ** (1/2)+ mp x0 y0 x1 y1 = let dist = ((x1 - x0) ** 2 + (y1 - y0) ** 2) ** (1 / 2)+ in take (floor $ dist / step) $ zip+ [x0, x0 + step * (x1 - x0) / dist .. ]+ [y0, y0 + step * (y1 - y0) / dist .. ] directions :: TurtleState -> TurtleState -> [Double] directions t0 t1 = case directionStep t0 of Nothing -> []- Just step -> let dd = if de > ds then step else - step in- [ds, ds + dd .. de - dd]- where- ds = direction t0- de = direction t1+ Just step -> [ds, ds + dd .. de - dd]+ where+ dd = if de > ds then step else - step+ ds = direction t0+ de = direction t1 -drawTurtle :: Field -> Character -> TurtleState -> Double ->- (Double, Double) -> Maybe (Double, Double) -> IO ()-drawTurtle f c t d (px, py) = maybe (drawCharacter f c (pencolor t) sp)- (uncurry $ drawCharacterAndLine f c (pencolor t) sp (pensize t) px py)- where- sp = let (sx, sy) = shapesize t in- map (((+ px) *** (+ py)) . rotate . ((* sx) *** (* sy))) $ shape t- rotate (x, y) = let rad = d in- (x * cos rad - y * sin rad, x * sin rad + y * cos rad)+drawTurtle :: Field -> Character -> TurtleState -> Double -> Position ->+ Maybe Position -> IO ()+drawTurtle f c ts@TurtleState{pencolor = clr} dir pos = maybe+ (drawCharacter f c clr $ makeShape ts dir pos)+ (drawCharacterAndLine f c clr (makeShape ts dir pos) (pensize ts) pos)
src/Graphics/X11/Turtle/State.hs view
@@ -1,62 +1,72 @@-module Graphics.X11.Turtle.State (- TurtleState(..),- initialTurtleState-) where+module Graphics.X11.Turtle.State(+ TurtleState(..), initialTurtleState, makeShape) where -import Text.XML.YJSVG(SVG(Fill), Color(RGB))+import Text.XML.YJSVG(Position(..), SVG(Fill), Color(RGB))+import Control.Arrow((***))+import Data.Tuple.Tools(rotate) data TurtleState = TurtleState {- position :: (Double, Double),- positionStep :: Maybe Double,+ position :: Position, direction :: Double, degrees :: Double,- directionStep :: Maybe Double,- interval :: Int,- pendown :: Bool,- fill :: Bool,- poly :: Bool,- pensize :: Double,- pencolor :: Color,- bgcolor :: Color, shape :: [(Double, Double)], shapesize :: (Double, Double),+ pensize :: Double,+ pencolor :: Color,+ pendown :: Bool, visible :: Bool,+ stepbystep :: Bool,++ draw :: Maybe SVG,+ drawed :: [SVG], clear :: Bool, undo :: Bool, undonum :: Int,- draw :: Maybe SVG,- drawed :: [SVG],- fillPoints :: [(Double, Double)],- polyPoints :: [(Double, Double)], sleep :: Maybe Int,- stepbystep :: Bool,- flush :: Bool}- deriving Show+ flush :: Bool,+ fill :: Bool,+ poly :: Bool,+ fillPoints :: [Position],+ polyPoints :: [Position], + positionStep :: Maybe Double,+ directionStep :: Maybe Double,+ interval :: Int}+ initialTurtleState :: TurtleState initialTurtleState = TurtleState {- position = (0, 0),- positionStep = Just 10,+ position = Center 0 0, direction = 0, degrees = 360,- directionStep = Just $ pi / 18,- interval = 10000,- pendown = True,- fill = False,- poly = False,- pensize = 1,- pencolor = RGB 0 0 0,- bgcolor = RGB 255 255 255, shape = [], shapesize = (1, 1),+ pensize = 1,+ pencolor = RGB 0 0 0,+ pendown = True, visible = True,+ stepbystep = True,++ draw = Nothing,+ drawed = [Fill $ RGB 255 255 255], clear = False, undo = False, undonum = 0,- draw = Nothing,- drawed = [Fill $ RGB 255 255 255],+ sleep = Nothing,+ flush = False,+ fill = False,+ poly = False, fillPoints = [], polyPoints = [],- sleep = Nothing,- stepbystep = True,- flush = False}++ positionStep = Just 10,+ directionStep = Just $ pi / 18,+ interval = 10000}++makeShape :: TurtleState -> Double -> Position -> [Position]+makeShape ts dir_ pos = (mkPos . move . rotate dir . resize) `map` shape ts+ where+ move = (+ posX pos) *** (+ posY pos)+ resize = uncurry (***) $ ((*) *** (*)) $ shapesize ts+ (mkPos, dir) = case pos of+ Center{} -> (uncurry Center, dir_)+ TopLeft{} -> (uncurry TopLeft, - dir_)
src/Graphics/X11/Turtle/XTools.hs view
@@ -6,7 +6,7 @@ XIC, Atom, Point(..),- Position,+ PositionXT, Dimension, Bufs, undoBuf,@@ -29,10 +29,9 @@ -- * draw functions flush,- colorPixel,- setForeground,+ setForegroundXT, copyArea,- fillRectangle,+ fillRectangleXT, fillPolygonXT, drawLineXT, writeStringXT,@@ -54,7 +53,7 @@ import Text.XML.YJSVG(Color(..)) import Graphics.X11(- Display, Drawable, Window, Pixmap, GC, Pixel, Atom, Point(..), Position,+ Display, Drawable, Window, Pixmap, GC, Atom, Point(..), Position, Dimension, XEventPtr, initThreads, flush, supportsLocale, setLocaleModifiers, connectionNumber, openDisplay, closeDisplay, internAtom,@@ -97,6 +96,7 @@ -------------------------------------------------------------------------------- +type PositionXT = Position data Bufs = Bufs{undoBuf :: Pixmap, bgBuf :: Pixmap, topBuf :: Pixmap} data GCs = GCs{gcForeground :: GC, gcBackground :: GC} @@ -139,20 +139,26 @@ -------------------------------------------------------------------------------- -colorPixel :: Display -> Color -> IO (Maybe Pixel)-colorPixel _ (RGB r g b) = return $ Just $ shift (fromIntegral r) 16 .|.- shift (fromIntegral g) 8 .|. fromIntegral b-colorPixel dpy (ColorName cn) = fmap (Just . color_pixel . fst)- (allocNamedColor dpy (defaultColormap dpy $ defaultScreen dpy) cn)- `catch` const (putStrLn "no such color" >> return Nothing)+setForegroundXT :: Display -> GC -> Color -> IO ()+setForegroundXT dpy gc (RGB r g b) =+ setForeground dpy gc $ shift (fromIntegral r) 16 .|.+ shift (fromIntegral g) 8 .|. fromIntegral b+setForegroundXT dpy gc (ColorName cn) =+ (allocNamedColor dpy (defaultColormap dpy $ defaultScreen dpy) cn+ >>= setForeground dpy gc . color_pixel . fst)+ `catch` const (putStrLn "no such color") +fillRectangleXT :: Display -> Drawable -> GC ->+ Position -> Position -> Dimension -> Dimension -> IO ()+fillRectangleXT = fillRectangle+ fillPolygonXT :: Display -> Drawable -> GC -> [Point] -> IO () fillPolygonXT d w gc ps = fillPolygon d w gc ps nonconvex coordModeOrigin drawLineXT :: Display -> GC -> Drawable -> Int -> Color -> Position -> Position -> Position -> Position -> IO ()-drawLineXT dpy gc buf lw c x1 y1 x2 y2 = do- colorPixel dpy c >>= maybe (return ()) (setForeground dpy gc)+drawLineXT dpy gc buf lw clr x1 y1 x2 y2 = do+ setForegroundXT dpy gc clr setLineAttributes dpy gc (fromIntegral lw) lineSolid capRound joinRound drawLine dpy buf gc x1 y1 x2 y2 @@ -170,8 +176,8 @@ where color = XRenderColor { xrendercolor_red = fromIntegral r * 0x100,- xrendercolor_green = fromIntegral b * 0x100, xrendercolor_blue = fromIntegral g * 0x100,+ xrendercolor_green = fromIntegral b * 0x100, xrendercolor_alpha = 0xffff} ColorName cn -> withXftColorName dpy visual colormap cn $ \c -> xftDrawString xftDraw c xftFont x y str@@ -187,9 +193,9 @@ case err of ImlibLoadErrorNone -> do contextSetImage img- let zero = 0 :: Int- w <- fmap fromIntegral imageGetWidth :: IO Int- h <- fmap fromIntegral imageGetHeight :: IO Int+ let zero = 0 :: Position+ w <- fmap fromIntegral imageGetWidth :: IO Dimension+ h <- fmap fromIntegral imageGetHeight :: IO Dimension img' <- createCroppedScaledImage zero zero w h nw nh contextSetImage img' fmap Just imageGetData@@ -197,14 +203,13 @@ drawBitmap :: Display -> Drawable -> GC -> Position -> Position -> Dimension -> Dimension -> Ptr Word32 -> IO ()-drawBitmap dpy win gc x0 y0 w h dat = do+drawBitmap dpy win gc x0 y0 w_ h_ dat = do ptr <- newIORef dat- forM_ [0 .. w * h - 1] $ \i -> do+ forM_ [0 .. w * h - 1] $ \i -> do readIORef ptr >>= peek >>= setForeground dpy gc- let x = fromIntegral i `mod` w- y = fromIntegral i `div` w- drawPoint dpy win gc (x0 + fromIntegral x) (y0 + fromIntegral y)+ drawPoint dpy win gc (x0 + i `mod` w) (y0 + i `div` w) atomicModifyIORef_ ptr $ flip advancePtr 1+ where [w, h] = map fromIntegral [w_, h_] --------------------------------------------------------------------------------
xturtle.cabal view
@@ -2,7 +2,7 @@ cabal-version: >= 1.6 name: xturtle-version: 0.1.6+version: 0.1.9 stability: experimental author: Yoshikuni Jujo <PAF01143@nifty.ne.jp> maintainer: Yoshikuni Jujo <PAF01143@nifty.ne.jp>@@ -30,8 +30,8 @@ library Hs-source-dirs: src Exposed-modules: Graphics.X11.Turtle- Build-depends: base > 3 && < 5, yjtools >= 0.9.14, convertible >= 1.0.8, X11,- X11-xft <= 3.1, x11-xim, setlocale, yjsvg >= 0.1.13, Imlib >= 0.1.2+ Build-depends: base > 3 && < 5, yjtools >= 0.9.15, convertible >= 1.0.8, X11,+ X11-xft <= 3.1, x11-xim, setlocale, yjsvg >= 0.1.14, Imlib >= 0.1.2 Ghc-options: -Wall Other-modules: Graphics.X11.Turtle.Field, Graphics.X11.Turtle.Input, Graphics.X11.Turtle.Move, Graphics.X11.Turtle.State, Graphics.X11.Turtle.Data,