xturtle 0.1.9 → 0.1.11
raw patch · 9 files changed
+230/−267 lines, 9 filesdep ~yjtools
Dependency ranges changed: yjtools
Files
- src/Graphics/X11/Turtle.hs +12/−11
- src/Graphics/X11/Turtle/Data.hs +1/−2
- src/Graphics/X11/Turtle/Field.hs +117/−108
- src/Graphics/X11/Turtle/Input.hs +26/−45
- src/Graphics/X11/Turtle/Layers.hs +29/−53
- src/Graphics/X11/Turtle/Move.hs +6/−6
- src/Graphics/X11/Turtle/State.hs +4/−4
- src/Graphics/X11/Turtle/XTools.hs +33/−36
- xturtle.cabal +2/−2
src/Graphics/X11/Turtle.hs view
@@ -93,19 +93,19 @@ ) where import Graphics.X11.Turtle.Data(shapeTable, speedTable)-import Graphics.X11.Turtle.Input(- TurtleState, TurtleInput(..),- turtleSeries, direction, visible, undonum, drawed, polyPoints)-import qualified Graphics.X11.Turtle.Input as S(position, degrees, pendown)+import Graphics.X11.Turtle.State(+ TurtleState, direction, visible, undonum, drawed, polyPoints)+import qualified Graphics.X11.Turtle.State as S(position, degrees, pendown)+import Graphics.X11.Turtle.Input(TurtleInput(..), turtleSeries) import Graphics.X11.Turtle.Move(- Field, Coordinates(..), openField, closeField, fieldSize,- coordinates, topleft, center, waitField, forkField, flushField,+ Field, Coordinates(..), openField, closeField, waitField,+ topleft, center, coordinates, fieldSize, forkField, flushField, addLayer, clearLayer, addCharacter, clearCharacter, moveTurtle, onclick, onrelease, ondrag, onmotion, onkeypress, ontimer) import Text.XML.YJSVG(SVG(..), Position(..), Color(..)) import qualified Text.XML.YJSVG as S(center, topleft) -import Control.Concurrent(killThread, writeChan)+import Control.Concurrent(killThread, newChan, writeChan, getChanContents) import Control.Monad(replicateM_, zipWithM_) import Control.Arrow((&&&)) import Data.IORef(IORef, newIORef, readIORef)@@ -115,7 +115,7 @@ -------------------------------------------------------------------------------- xturtleVersion :: (Int, String)-xturtleVersion = (65, "0.1.9")+xturtleVersion = (69, "0.1.11") -------------------------------------------------------------------------------- @@ -138,7 +138,8 @@ newTurtle :: Field -> IO Turtle newTurtle f = do index <- newIORef 1; shapesRef <- newIORef shapeTable- (chan, hist, states) <- turtleSeries+ chan <- newChan; hist <- getChanContents chan+ let states = turtleSeries hist l <- addLayer f; c <- addCharacter f thr <- forkField f $ zipWithM_ (moveTurtle f c l) states $ tail states let t = Turtle {@@ -326,8 +327,8 @@ isvisible = flip info visible windowWidth, windowHeight :: Turtle -> IO Double-windowWidth = fmap fst . fieldSize . field-windowHeight = fmap snd . fieldSize . field+windowWidth = fmap fst . windowSize+windowHeight = fmap snd . windowSize windowSize :: Turtle -> IO (Double, Double) windowSize = fieldSize . field
src/Graphics/X11/Turtle/Data.hs view
@@ -1,7 +1,6 @@ module Graphics.X11.Turtle.Data( -- * tables- shapeTable, speedTable-) where+ shapeTable, speedTable) where import Control.Arrow(second, (&&&))
src/Graphics/X11/Turtle/Field.hs view
@@ -46,10 +46,10 @@ import Graphics.X11.Turtle.XTools( Display, Window, Pixmap, Atom, Point(..), PositionXT, Dimension,- XEventPtr, XIC, Bufs, undoBuf, bgBuf, topBuf,- GCs, gcForeground, gcBackground, Event(..),+ XEventPtr, Event(..), XIC, Bufs, undoBuf, bgBuf, topBuf,+ GCs, gcForeground, gcBackground, forkIOX, openWindow, destroyWindow, closeDisplay, windowSize,- flush, copyArea, setForegroundXT,+ flush, setForegroundXT, copyAreaXT, drawLineXT, fillRectangleXT, fillPolygonXT, writeStringXT, drawImageXT, allocaXEvent, waitEvent, pending, nextEvent, getEvent, filterEvent, utf8LookupString, buttonPress, buttonRelease, xK_VoidSymbol)@@ -59,8 +59,8 @@ makeCharacter, character) import Text.XML.YJSVG(Position(..), Color(..)) -import Control.Monad(when, unless, forever, replicateM, join)-import Control.Monad.Tools(doWhile_, doWhile, whenM)+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,@@ -68,7 +68,9 @@ 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) -------------------------------------------------------------------------------- @@ -77,23 +79,24 @@ fIC :: XIC, fDel :: Atom, fSize :: IORef (Dimension, Dimension), fClick, fRelease :: IORef (Int -> Double -> Double -> IO Bool),- fDrag, fMotion :: IORef (Double -> Double -> IO ()),- fKeypress :: IORef (Char -> IO Bool),- fTimerEvent :: IORef (IO Bool),- fPressed :: IORef Bool,+ fDrag :: IORef (Int -> Double -> Double -> IO ()),+ fPressed :: IORef [Int],+ fMotion :: IORef (Double -> Double -> IO ()),+ fKeypress :: IORef (Char -> IO Bool), fTimerEvent :: IORef (IO Bool), - fLayers :: IORef Layers, fInput :: Chan InputType,- fCoordinates :: IORef Coordinates, fLock, fClose, fEnd :: Chan (),+ fLayers :: IORef Layers, fCoordinates :: IORef Coordinates,+ fInput :: Chan InputType, 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, motion] <- replicateM 2 $ newIORef $ \_ _ -> return ()- keypress <- newIORef $ \_ -> return True+ [click, release] <- replicateM 2 $ newIORef $ const3 $ return True+ drag <- newIORef $ const3 $ return ()+ pressed <- newIORef []+ motion <- newIORef $ const2 $ return ()+ keypress <- newIORef $ const $ return True timer <- newIORef $ return True- pressed <- newIORef False input <- newChan coord <- newIORef CoordCenter [lock, close, end] <- replicateM 3 newChan@@ -103,37 +106,35 @@ fDisplay = dpy, fWindow = win, fBufs = bufs, fGCs = gcs, fIC = ic, fDel = del, fSize = sizeRef, - fClick = click, fRelease = release, fDrag = drag,+ fClick = click, fRelease = release,+ fDrag = drag, fPressed = pressed, fMotion = motion, fKeypress = keypress, fTimerEvent = timer,- fPressed = pressed, - fLayers = ls, fInput = input, fCoordinates = coord,+ fLayers = ls, fCoordinates = coord, fInput = input, fLock = lock, fClose = close, fEnd = end, fRunning = running} -data Coordinates = CoordCenter | CoordTopLeft+setPressed :: Field -> Int -> Bool -> IO ()+setPressed f buttonN True = atomicModifyIORef_ (fPressed f) (buttonN :)+setPressed f buttonN False = atomicModifyIORef_ (fPressed f) (delete buttonN) -coordinates :: Field -> IO Coordinates-coordinates = readIORef . fCoordinates+killRunning :: Field -> IO ()+killRunning f = readIORef (fRunning f) >>= mapM_ killThread -topleft, center :: Field -> IO ()-topleft = flip (writeIORef . fCoordinates) CoordTopLeft-center = flip (writeIORef . fCoordinates) CoordCenter+data Coordinates = CoordCenter | CoordTopLeft -------------------------------------------------------------------------------- openField :: IO Field openField = do (dpy, win, bufs, gcs, ic, del, size) <- openWindow+ sizeRef <- newIORef size let (ub, bb, tb) = (undoBuf bufs, bgBuf bufs, topBuf bufs) (gcf, gcb) = (gcForeground gcs, gcBackground gcs)- sizeRef <- newIORef size- let getSize = readIORef sizeRef- ls <- newLayers 50 - (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+ lyrs <- newLayers 50 (setForegroundXT dpy gcb (RGB 255 255 255) >>+ readIORef sizeRef >>= uncurry (fillRectangleXT dpy ub gcb 0 0))+ (readIORef sizeRef >>= uncurry (copyAreaXT dpy ub bb gcf))+ (readIORef sizeRef >>= uncurry (copyAreaXT dpy bb tb gcf))+ f <- makeField dpy win bufs gcs ic del sizeRef lyrs _ <- forkIOX $ runLoop f flush dpy return f@@ -144,14 +145,11 @@ waitInput f = do empty <- newChan tid <- forkIOX $ forever $ do- waitEvent $ fDisplay f- writeChan (fInput f) XInput+ waitEvent (fDisplay f) >> writeChan (fInput f) XInput readChan empty atomicModifyIORef_ (fRunning f) (tid :)- _ <- forkIO $ do- readChan $ fClose f- killThread tid- writeChan (fInput f) End+ _ <- forkIO $+ readChan (fClose f) >> killRunning f >> writeChan (fInput f) End return empty runLoop :: Field -> IO ()@@ -159,28 +157,32 @@ empty <- waitInput f doWhile_ $ do iType <- readChan $ fInput f- cont <- case iType of+ case iType of End -> return False Timer -> do- c <- join $ readIORef $ fTimerEvent f- 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)- if cont then writeChan empty () >> return True else return False- readIORef (fRunning f) >>= mapM_ killThread+ cont <- join $ readIORef $ fTimerEvent f+ unless cont $ killRunning f+ return cont+ XInput -> do+ cont <- processXInput f e+ when cont $ writeChan empty ()+ return cont destroyWindow (fDisplay f) (fWindow f) closeDisplay $ fDisplay f writeChan (fEnd f) () +processXInput :: Field -> XEventPtr -> IO Bool+processXInput f e = 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 (undefined, True) else do+ ev <- getEvent e+ c <- processEvent f e ev+ unless c $ killRunning f+ return (c && undefined, c)+ processEvent :: Field -> XEventPtr -> Event -> IO Bool processEvent f e ev = case ev of ExposeEvent{} -> flushField f True $ do@@ -192,41 +194,51 @@ _ks = fromMaybe xK_VoidSymbol mks readIORef (fKeypress f) >>= fmap and . ($ str) . mapM ButtonEvent{} -> do- 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+ let buttonN = fromIntegral $ ev_button ev+ pos <- getEventXY f ev case ev_event_type ev of et | et == buttonPress -> do- writeIORef (fPressed f) True+ setPressed f buttonN True readIORef (fClick f) >>= ($ pos) . uncurry . ($ buttonN) | et == buttonRelease -> do- writeIORef (fPressed f) False+ setPressed f buttonN False readIORef (fRelease f) >>= ($ pos) . uncurry . ($ buttonN) _ -> error "not implement event" MotionEvent{} -> do- pos <- cntr (ev_x ev) (ev_y ev)- whenM (readIORef $ fPressed f) $- readIORef (fDrag f) >>= ($ pos) . uncurry+ pos <- getEventXY f ev+ pressed <- readIORef $ fPressed f+ forM_ pressed $ \bn -> readIORef (fDrag f) >>=+ ($ pos) . uncurry . ($ bn) readIORef (fMotion f) >>= ($ pos) . uncurry return True ClientMessageEvent{} -> return $ convert (head $ ev_data ev) /= fDel f _ -> return True- where- cntr x y = do- (w, h) <- fieldSize f- return (fromIntegral x - w / 2, fromIntegral (- y) + h / 2) +getEventXY :: Field -> Event -> IO (Double, Double)+getEventXY f ev = do+ let [x, y] = map (fromIntegral . ($ ev)) [ev_x, ev_y]+ coord <- readIORef $ fCoordinates f+ case coord of+ CoordCenter -> do+ (w, h) <- fieldSize f+ return (x - w / 2, h / 2 - y)+ CoordTopLeft -> return (x, y)+ closeField :: Field -> IO () closeField = flip writeChan () . fClose waitField :: Field -> IO () waitField = readChan . fEnd +topleft, center :: Field -> IO ()+topleft = flip (writeIORef . fCoordinates) CoordTopLeft+center = flip (writeIORef . fCoordinates) CoordCenter++coordinates :: Field -> IO Coordinates+coordinates = readIORef . fCoordinates+ fieldSize :: Field -> IO (Double, Double) fieldSize = fmap (fromIntegral *** fromIntegral) . readIORef . fSize @@ -238,20 +250,19 @@ atomicModifyIORef_ (fRunning f) (tid :) >> return tid flushField :: Field -> Bool -> IO a -> IO a-flushField f real act = do+flushField f@Field{fDisplay = dpy, fWindow = win} real act = do 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+ let (tb, gc) = (topBuf $ fBufs f, gcForeground $ fGCs f)+ uncurry (copyAreaXT dpy tb win gc) =<< readIORef (fSize f) flush $ fDisplay f writeChan (fLock f) () >> return ret fieldColor :: Field -> Layer -> Color -> IO ()-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)+fieldColor f@Field{fDisplay = dpy} l clr = background l $ do+ let (ub, gc) = (undoBuf $ fBufs f, gcBackground $ fGCs f)+ setForegroundXT dpy gc clr+ uncurry (fillRectangleXT dpy ub gc 0 0) =<< readIORef (fSize f) -------------------------------------------------------------------------------- @@ -259,13 +270,17 @@ addLayer = makeLayer . fLayers drawLayer :: Field -> Layer -> (Pixmap -> IO ()) -> IO ()-drawLayer Field{fBufs = bufs} l draw =- addDraw l (draw $ undoBuf bufs, draw $ bgBuf bufs)+drawLayer Field{fBufs = bs} l drw = addDraw l (drw $ undoBuf bs, drw $ bgBuf bs) 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+drawLine f l w c p q = drawLayer f l $ \buf -> drawLineBuf f buf (round w) c p q +drawLineBuf :: Field -> Pixmap -> Int -> Color -> Position -> Position -> IO ()+drawLineBuf f@Field{fDisplay = dpy} buf lw clr p q = do+ (x1, y1) <- getPosition f p+ (x2, y2) <- getPosition f q+ drawLineXT dpy (gcForeground $ fGCs f) buf lw clr x1 y1 x2 y2+ writeString :: Field -> Layer -> String -> Double -> Color -> Position -> String -> IO () writeString f@Field{fDisplay = dpy} l fname size clr pos str =@@ -277,24 +292,21 @@ (x, y) <- getPosition f pos drawImageXT dpy buf (gcForeground $ fGCs f) fp x y (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- 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) -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+fillPolygon :: Field -> Layer -> [Position] -> Color -> IO ()+fillPolygon f l ps clr = drawLayer f l $ \buf -> fillPolygonBuf f buf clr ps +fillPolygonBuf :: Field -> Pixmap -> Color -> [Position] -> IO ()+fillPolygonBuf f@Field{fDisplay = dpy} buf clr positions = do+ ps <- mapM (fmap (uncurry Point) . getPosition f) positions+ setForegroundXT dpy (gcForeground $ fGCs f) clr+ fillPolygonXT dpy buf (gcForeground $ fGCs f) ps+ getPosition :: Field -> Position -> IO (PositionXT, PositionXT) getPosition f (Center x y) = do (w, h) <- fieldSize f@@ -307,36 +319,33 @@ addCharacter = makeCharacter . fLayers drawCharacter :: Field -> Character -> Color -> [Position] -> IO ()-drawCharacter f c clr sh = character c $ drawShape f clr sh+drawCharacter f ch c = character ch . fillPolygonBuf f (topBuf $ fBufs f) c 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 -> [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+drawCharacterAndLine f ch clr sh lw p q = character ch $ do+ fillPolygonBuf f (topBuf $ fBufs f) clr sh+ drawLineBuf f (topBuf $ fBufs f) (round lw) clr p q clearCharacter :: Character -> IO ()-clearCharacter c = character c $ return ()+clearCharacter ch = character ch $ return () -------------------------------------------------------------------------------- onclick, onrelease :: Field -> (Int -> Double -> Double -> IO Bool) -> IO ()-(onclick, onrelease) = (writeIORef . fClick, writeIORef . fRelease)+[onclick, onrelease] = map (writeIORef .) [fClick, fRelease] -ondrag, onmotion :: Field -> (Double -> Double -> IO ()) -> IO ()-(ondrag, onmotion) = (writeIORef . fDrag, writeIORef . fMotion)+ondrag :: Field -> (Int -> Double -> Double -> IO ()) -> IO ()+ondrag = writeIORef . fDrag +onmotion :: Field -> (Double -> Double -> IO ()) -> IO ()+onmotion = writeIORef . fMotion+ onkeypress :: Field -> (Char -> IO Bool) -> IO () onkeypress = writeIORef . fKeypress ontimer :: Field -> Int -> IO Bool -> IO () ontimer f t fun = do writeIORef (fTimerEvent f) fun- threadDelay $ t * 1000- writeChan (fInput f) Timer+ _ <- forkIO $ threadDelay (t * 1000) >> writeChan (fInput f) Timer+ return ()
src/Graphics/X11/Turtle/Input.hs view
@@ -1,31 +1,14 @@-module Graphics.X11.Turtle.Input(- -- * types- TurtleState,- TurtleInput(..),-- -- * get TurtlsStates in timeline- turtleSeries,-- -- * read TurtleState members- position,- direction,- degrees,- pendown,- visible,- undonum,- drawed,- polyPoints-) where+module Graphics.X11.Turtle.Input(TurtleInput(..), turtleSeries) where -import Graphics.X11.Turtle.State(TurtleState(..), initialTurtleState, makeShape)+import Graphics.X11.Turtle.State(TurtleState(..), initTurtleState, makeShape) import Text.XML.YJSVG(SVG(..), Color(..), Position(..))-import Control.Concurrent.Chan(Chan, newChan, getChanContents) -------------------------------------------------------------------------------- data TurtleInput = Goto Position | Forward Double+ | RotateRad Double | Rotate Double | TurnLeft Double | Dot Double@@ -52,31 +35,29 @@ | Degrees Double deriving (Show, Read) -turtleSeries :: IO (Chan TurtleInput, [TurtleInput], [TurtleState])-turtleSeries = do- let ts0 = initialTurtleState- c <- newChan- tis <- getChanContents c- return (c, tis, ts0 : ts0 : inputToTurtle [] ts0 tis)+turtleSeries :: [TurtleInput] -> [TurtleState]+turtleSeries tis = let ts0 = initTurtleState in ts0 : ts0 : turtles [] ts0 tis -inputToTurtle :: [TurtleState] -> TurtleState -> [TurtleInput] -> [TurtleState]-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) = case position ts0 of+turtles :: [TurtleState] -> TurtleState -> [TurtleInput] -> [TurtleState]+turtles [] ts0 (Undo : tis) = ts0 : turtles [] ts0 tis+turtles (tsb : tsbs) _ (Undo : tis) =+ let ts1 = tsb{undo = True} in ts1 : turtles tsbs ts1 tis+turtles 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+ turtles 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"+ turtles tsbs ts0 $ Goto (TopLeft x y) : tis+turtles tsbs ts0 (Rotate dir : tis) = turtles tsbs ts0 $+ RotateRad (dir * 2 * pi / degrees ts0) : tis+turtles tsbs ts0 (TurnLeft dd : tis) = turtles tsbs ts0 $+ RotateRad (direction ts0 + dd * 2 * pi / degrees ts0) : tis+turtles tsbs ts0 (ti : tis) =+ let ts1 = nextTurtle ts0 ti in ts1 : turtles (ts0 : tsbs) ts1 tis+turtles _ _ [] = error "no more input" reset :: TurtleState -> TurtleState reset t = t{draw = Nothing, clear = False, undo = False, undonum = 1,@@ -91,13 +72,13 @@ 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 (RotateRad dir) = (reset t){direction = dir}+nextTurtle t@TurtleState{pencolor = clr} (Dot sz) = reset t `set`+ Just (Rect (position t) sz sz 0 clr clr) 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@TurtleState{pencolor = clr} (Write fnt sz str) = reset t `set`+ Just (Text (position t) sz clr 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]}@@ -112,8 +93,8 @@ 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)+ `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}
src/Graphics/X11/Turtle/Layers.hs view
@@ -26,63 +26,48 @@ -------------------------------------------------------------------------------- data Layers = Layers{- backgrounds :: [IO ()],- buffers :: [IO ()],- layers :: [[(IO (), IO ())]],- characters :: [IO ()],- buffSize :: Int,- clearBuffers :: IO (),- clearLayers :: IO (),- clearCharacters :: IO ()}--data Layer = Layer{- layerId :: Int,- layerLayers :: IORef Layers- }+ bgs :: [IO ()], buffs :: [IO ()], layers :: [[(IO (), IO ())]],+ chars :: [IO ()], buffSize :: Int,+ clearBuffers :: IO (), clearLayers :: IO (), clearCharacters :: IO ()} -data Character = Character{- characterId :: Int,- characterLayers :: IORef Layers- }+data Layer = Layer{layerId :: Int, layerLayers :: IORef Layers}+data Character = Character{charId :: Int, charLayers :: IORef Layers} -------------------------------------------------------------------------------- newLayers :: Int -> IO () -> IO () -> IO () -> IO (IORef Layers) newLayers bsize cbuf clyr cchr = newIORef Layers{- backgrounds = [],- buffers = [],- layers = [],- characters = [],- buffSize = bsize,- clearBuffers = cbuf,- clearLayers = clyr,- clearCharacters = cchr}+ bgs = [], buffs = [], layers = [], chars = [], buffSize = bsize,+ clearBuffers = cbuf, clearLayers = clyr, clearCharacters = cchr} makeLayer :: IORef Layers -> IO Layer makeLayer rls = atomicModifyIORef rls $ \ls -> (ls{- backgrounds = backgrounds ls ++[return ()],- buffers = buffers ls ++ [return ()],+ bgs = bgs ls ++[return ()], buffs = buffs ls ++ [return ()], layers = layers ls ++ [[]]}, Layer{layerId = length $ layers ls, layerLayers = rls}) makeCharacter :: IORef Layers -> IO Character-makeCharacter rls = atomicModifyIORef rls $ \ls ->- (ls{characters = characters ls ++ [return ()]}, Character{- characterId = length $ characters ls,- characterLayers = rls})+makeCharacter rls = atomicModifyIORef rls $ \ls -> (ls{+ chars = chars ls ++ [return ()]},+ Character{charId = length $ chars ls, charLayers = rls}) -------------------------------------------------------------------------------- redrawLayers :: IORef Layers -> IO () redrawLayers rls = readIORef rls >>= \ls -> do- clearBuffers ls >> sequence_ (backgrounds ls) >> sequence_ (buffers ls)+ clearBuffers ls >> sequence_ (bgs ls) >> sequence_ (buffs ls) clearLayers ls >> mapM_ snd (concat $ layers ls)- clearCharacters ls >> sequence_ (characters ls)+ clearCharacters ls >> sequence_ (chars ls) +background :: Layer -> IO () -> IO ()+background Layer{layerId = lid, layerLayers = rls} act =+ atomicModifyIORef_ rls (\ls -> ls{bgs = setAt (bgs ls) lid act})+ >> redrawLayers rls+ addDraw :: Layer -> (IO (), IO ()) -> IO () addDraw Layer{layerId = lid, layerLayers = rls} acts@(_, act) = do readIORef rls >>= \ls -> do- act >> clearCharacters ls >> sequence_ (characters ls)+ act >> clearCharacters ls >> sequence_ (chars ls) unless (length (layers ls !! lid) < buffSize ls) $ fst $ head $ layers ls !! lid atomicModifyIORef_ rls $ \ls ->@@ -90,13 +75,7 @@ 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)}--background :: Layer -> IO () -> IO ()-background Layer{layerId = lid, layerLayers = rls} act = do- atomicModifyIORef_ rls $ \ls ->- ls{backgrounds = setAt (backgrounds ls) lid act}- redrawLayers rls+ buffs = modifyAt (buffs ls) lid (>> a)} undoLayer :: Layer -> IO Bool undoLayer Layer{layerId = lid, layerLayers = rls} = do@@ -105,20 +84,17 @@ else (ls{layers = modifyAt (layers ls) lid init}, True) when done $ readIORef rls >>= \ls -> do clearLayers ls >> mapM_ snd (concat $ layers ls)- clearCharacters ls >> sequence_ (characters ls)+ clearCharacters ls >> sequence_ (chars ls) return done clearLayer :: Layer -> IO ()-clearLayer Layer{layerId = lid, layerLayers = rls} = do- atomicModifyIORef_ rls $ \ls -> ls{- backgrounds = setAt (backgrounds ls) lid $ return (),- buffers = setAt (buffers ls) lid $ return (),- layers = setAt (layers ls) lid []}- redrawLayers rls+clearLayer Layer{layerId = lid, layerLayers = rls} =+ atomicModifyIORef_ rls (\ls -> ls{+ bgs = setAt (bgs ls) lid $ return (),+ buffs = setAt (buffs ls) lid $ return (),+ layers = setAt (layers ls) lid []}) >> redrawLayers rls 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 ->- clearCharacters ls >> sequence_ (characters ls)+character Character{charId = cid, charLayers = rls} act = do+ atomicModifyIORef_ rls $ \ls -> ls{chars = setAt (chars ls) cid act}+ readIORef rls >>= \ls -> clearCharacters ls >> sequence_ (chars ls)
src/Graphics/X11/Turtle/Move.hs view
@@ -6,11 +6,11 @@ -- * process Field openField, closeField,- fieldSize,- coordinates,+ waitField, topleft, center,- waitField,+ coordinates,+ fieldSize, -- * draws forkField,@@ -33,9 +33,9 @@ import Graphics.X11.Turtle.State(TurtleState(..), makeShape) import Graphics.X11.Turtle.Field( Field, Layer, Character, Coordinates(..),- openField, closeField, fieldSize, coordinates, topleft, center,- waitField, forkField, flushField,- addLayer, clearLayer, addCharacter, clearCharacter,+ openField, closeField, waitField, coordinates, topleft, center,+ fieldSize, forkField, flushField, addLayer, clearLayer,+ addCharacter, clearCharacter, onclick, onrelease, ondrag, onmotion, onkeypress, ontimer, fieldColor, drawLine, fillRectangle, fillPolygon, writeString, drawImage, undoLayer, drawCharacter, drawCharacterAndLine)
src/Graphics/X11/Turtle/State.hs view
@@ -1,9 +1,9 @@ module Graphics.X11.Turtle.State(- TurtleState(..), initialTurtleState, makeShape) where+ TurtleState(..), initTurtleState, makeShape) where import Text.XML.YJSVG(Position(..), SVG(Fill), Color(RGB))-import Control.Arrow((***)) import Data.Tuple.Tools(rotate)+import Control.Arrow((***)) data TurtleState = TurtleState { position :: Position,@@ -33,8 +33,8 @@ directionStep :: Maybe Double, interval :: Int} -initialTurtleState :: TurtleState-initialTurtleState = TurtleState {+initTurtleState :: TurtleState+initTurtleState = TurtleState { position = Center 0 0, direction = 0, degrees = 360,
src/Graphics/X11/Turtle/XTools.hs view
@@ -30,7 +30,7 @@ -- * draw functions flush, setForegroundXT,- copyArea,+ copyAreaXT, fillRectangleXT, fillPolygonXT, drawLineXT,@@ -50,8 +50,6 @@ xK_VoidSymbol, ) where -import Text.XML.YJSVG(Color(..))- import Graphics.X11( Display, Drawable, Window, Pixmap, GC, Atom, Point(..), Position, Dimension, XEventPtr,@@ -79,7 +77,7 @@ import Graphics.Imlib( ImlibLoadError(..), loadImageWithErrorReturn, contextSetImage, imageGetWidth, imageGetHeight, imageGetData, createCroppedScaledImage)-+import Text.XML.YJSVG(Color(..)) import Numeric(showFFloat) import Control.Monad(forM_, replicateM) import Control.Monad.Tools(unlessM)@@ -88,8 +86,7 @@ import System.Posix.Types(Fd(..)) import Data.Word(Word32) import Data.Bits((.|.), shift)-import Data.IORef(newIORef, readIORef)-import Data.IORef.Tools(atomicModifyIORef_)+import Data.IORef(newIORef, readIORef, modifyIORef) import Foreign.Ptr(Ptr) import Foreign.Storable(peek) import Foreign.Marshal.Array(advancePtr)@@ -103,7 +100,7 @@ -------------------------------------------------------------------------------- forkIOX :: IO () -> IO ThreadId-forkIOX = (initThreads >>) . forkIO+forkIOX = forkIO . (initThreads >>) openWindow :: IO (Display, Window, Bufs, GCs, XIC, Atom, (Dimension, Dimension)) openWindow = do@@ -113,7 +110,7 @@ _ <- setLocaleModifiers "" dpy <- openDisplay "" del <- internAtom dpy "WM_DELETE_WINDOW" True- let scr = defaultScreen dpy+ let scr = defaultScreen dpy root <- rootWindow dpy scr (rWidth, rHeight) <- windowSize dpy root bufs@[ub, bb, tb] <- replicateM 3 $@@ -140,16 +137,20 @@ -------------------------------------------------------------------------------- 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")+setForegroundXT dpy gc (RGB r_ g_ b_) = let+ [r, g, b] = map fromIntegral [r_, g_, b_] in+ setForeground dpy gc $ shift r 16 .|. shift g 8 .|. b+setForegroundXT dpy gc (ColorName cn) = let+ cm = defaultColormap dpy $ defaultScreen dpy in+ (allocNamedColor dpy cm cn >>= setForeground dpy gc . color_pixel . fst)+ `catch` const (putStrLn "no such color") -fillRectangleXT :: Display -> Drawable -> GC ->- Position -> Position -> Dimension -> Dimension -> IO ()+copyAreaXT :: Display -> Drawable -> Drawable -> GC ->+ Dimension -> Dimension -> IO ()+copyAreaXT dpy src dst gc w h = copyArea dpy src dst gc 0 0 w h 0 0++fillRectangleXT :: Display -> Drawable -> GC -> Position -> Position ->+ Dimension -> Dimension -> IO () fillRectangleXT = fillRectangle fillPolygonXT :: Display -> Drawable -> GC -> [Point] -> IO ()@@ -165,22 +166,19 @@ writeStringXT :: Display -> Drawable -> String -> Double -> Color -> Position -> Position -> String -> IO () writeStringXT dpy buf fname size clr x y str = do- let visual = defaultVisual dpy $ defaultScreen dpy- colormap = defaultColormap dpy $ defaultScreen dpy- font = fname ++ "-" ++ showFFloat (Just 0) size ""- xftDraw <- xftDrawCreate dpy buf visual colormap- xftFont <- xftFontOpen dpy (defaultScreenOfDisplay dpy) font- case clr of- RGB r g b -> withXftColorValue dpy visual colormap color $ \c ->- xftDrawString xftDraw c xftFont x y str- where- color = XRenderColor {+ let vsl = defaultVisual dpy $ defaultScreen dpy+ cm = defaultColormap dpy $ defaultScreen dpy+ withColor = case clr of+ RGB r g b -> withXftColorValue dpy vsl cm XRenderColor{ xrendercolor_red = fromIntegral r * 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+ ColorName cn -> withXftColorName dpy vsl cm cn+ draw <- xftDrawCreate dpy buf vsl cm+ font <- xftFontOpen dpy (defaultScreenOfDisplay dpy) $+ fname ++ "-" ++ showFFloat (Just 0) size ""+ withColor $ \c -> xftDrawString draw c font x y str drawImageXT :: Display -> Drawable -> GC -> FilePath -> Position -> Position -> Dimension -> Dimension -> IO ()@@ -193,22 +191,21 @@ case err of ImlibLoadErrorNone -> do contextSetImage img- 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 _ -> print err >> return Nothing+ where zero = 0 :: Position -drawBitmap :: Display -> Drawable -> GC -> Position -> Position -> Dimension ->- Dimension -> Ptr Word32 -> IO ()-drawBitmap dpy win gc x0 y0 w_ h_ dat = do- ptr <- newIORef dat+drawBitmap :: Display -> Drawable -> GC -> Position -> Position ->+ Dimension -> Dimension -> Ptr Word32 -> IO ()+drawBitmap dpy win gc x y w_ h_ dat = newIORef dat >>= \ptr -> forM_ [0 .. w * h - 1] $ \i -> do readIORef ptr >>= peek >>= setForeground dpy gc- drawPoint dpy win gc (x0 + i `mod` w) (y0 + i `div` w)- atomicModifyIORef_ ptr $ flip advancePtr 1+ drawPoint dpy win gc (x + i `mod` w) (y + i `div` w)+ modifyIORef 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.9+version: 0.1.11 stability: experimental author: Yoshikuni Jujo <PAF01143@nifty.ne.jp> maintainer: Yoshikuni Jujo <PAF01143@nifty.ne.jp>@@ -30,7 +30,7 @@ library Hs-source-dirs: src Exposed-modules: Graphics.X11.Turtle- Build-depends: base > 3 && < 5, yjtools >= 0.9.15, convertible >= 1.0.8, X11,+ Build-depends: base > 3 && < 5, yjtools >= 0.9.16, 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,