helm 0.1.0 → 0.2.0
raw patch · 7 files changed
+605/−254 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- FRP.Helm.Graphics: type Shape = [(Double, Double)]
- FRP.Helm.Keyboard: Keypad0Key :: Key
- FRP.Helm.Keyboard: Keypad1Key :: Key
- FRP.Helm.Keyboard: Keypad2Key :: Key
- FRP.Helm.Keyboard: Keypad3Key :: Key
- FRP.Helm.Keyboard: Keypad4Key :: Key
- FRP.Helm.Keyboard: Keypad5Key :: Key
- FRP.Helm.Keyboard: Keypad6Key :: Key
- FRP.Helm.Keyboard: Keypad7Key :: Key
- FRP.Helm.Keyboard: Keypad8Key :: Key
- FRP.Helm.Keyboard: Keypad9Key :: Key
+ FRP.Helm.Color: complement :: Color -> Color
+ FRP.Helm.Color: hsv :: Double -> Double -> Double -> Color
+ FRP.Helm.Color: hsva :: Double -> Double -> Double -> Double -> Color
+ FRP.Helm.Graphics: ArcShape :: (Double, Double) -> Double -> Double -> Double -> (Double, Double) -> Shape
+ FRP.Helm.Graphics: PolygonShape :: Path -> Shape
+ FRP.Helm.Graphics: RectangleShape :: (Double, Double) -> Shape
+ FRP.Helm.Graphics: data Shape
+ FRP.Helm.Graphics: fittedImage :: Int -> Int -> FilePath -> Element
+ FRP.Helm.Keyboard: KKey :: Key
+ FRP.Helm.Keyboard: KeypadNum0Key :: Key
+ FRP.Helm.Keyboard: KeypadNum1Key :: Key
+ FRP.Helm.Keyboard: KeypadNum2Key :: Key
+ FRP.Helm.Keyboard: KeypadNum3Key :: Key
+ FRP.Helm.Keyboard: KeypadNum4Key :: Key
+ FRP.Helm.Keyboard: KeypadNum5Key :: Key
+ FRP.Helm.Keyboard: KeypadNum6Key :: Key
+ FRP.Helm.Keyboard: KeypadNum7Key :: Key
+ FRP.Helm.Keyboard: KeypadNum8Key :: Key
+ FRP.Helm.Keyboard: KeypadNum9Key :: Key
+ FRP.Helm.Keyboard: ModeKey :: Key
+ FRP.Helm.Keyboard: instance Enum Key
+ FRP.Helm.Keyboard: isDown :: Key -> SignalGen (Signal Bool)
+ FRP.Helm.Keyboard: keysDown :: SignalGen (Signal [Key])
- FRP.Helm: degrees :: Float -> Float
+ FRP.Helm: degrees :: Double -> Double
- FRP.Helm: radians :: Float -> Float
+ FRP.Helm: radians :: Double -> Double
- FRP.Helm: turns :: Float -> Float
+ FRP.Helm: turns :: Double -> Double
- FRP.Helm.Graphics: polygon :: [(Double, Double)] -> Shape
+ FRP.Helm.Graphics: polygon :: Path -> Shape
Files
- FRP/Helm.hs +93/−17
- FRP/Helm/Color.hs +102/−8
- FRP/Helm/Graphics.hs +84/−53
- FRP/Helm/Keyboard.hs +306/−165
- FRP/Helm/Mouse.hs +14/−9
- FRP/Helm/Window.hs +5/−1
- helm.cabal +1/−1
FRP/Helm.hs view
@@ -1,8 +1,13 @@+{-| Contains miscellaneous utility functions and the main+ functions for interfacing with the engine. -} module FRP.Helm (+ -- * Engine+ run,+ -- * Utilities radians, degrees, turns,- run,+ -- * Prelude module FRP.Helm.Color, module FRP.Helm.Graphics, ) where@@ -20,6 +25,7 @@ {-| Attempt to change the window dimensions (and initialize the video mode if not already). Will try to get a hardware accelerated window and then fallback to a software one. Throws an exception if the software mode can't be used as a fallback. -}+-- TODO: userland version of this requestDimensions :: Int -> Int -> IO SDL.Surface requestDimensions w h = do mayhaps <- SDL.trySetVideoMode w h 32 [SDL.HWSurface, SDL.DoubleBuf, SDL.Resizable]@@ -28,19 +34,22 @@ Just screen -> return screen Nothing -> SDL.setVideoMode w h 32 [SDL.SWSurface, SDL.Resizable] --- |Converts radians into the standard angle measurement (radians).-radians :: Float -> Float+{-| Converts radians into the standard angle measurement (radians). -}+radians :: Double -> Double radians n = n --- |Converts degrees into the standard angle measurement (radians).-degrees :: Float -> Float+{-| Converts degrees into the standard angle measurement (radians). -}+degrees :: Double -> Double degrees n = n * pi / 180 {-| Converts turns into the standard angle measurement (radians). Turns are essentially full revolutions of the unit circle. -}-turns :: Float -> Float+turns :: Double -> Double turns n = 2 * pi * n +{-| A data structure describing the current engine state.+ This may be in userland in the future, for setting+ window dimensions, title, etc. -} data EngineState = EngineState { smp :: IO Element, {- FIXME: we need this mutable state (unfortunately) @@ -51,6 +60,7 @@ cache :: IORef (Map.Map FilePath Cairo.Surface) } +{-| Creates a new engine state, spawning an empty cache spawned in an IORef. -} newEngineState :: IO Element -> IO EngineState newEngineState smp = do cache <- newIORef Map.empty@@ -58,16 +68,34 @@ return EngineState { smp = smp, cache = cache } {-| Initializes and runs the game engine. The supplied signal generator is- constantly sampled for an element to render until the user quits. -}+ constantly sampled for an element to render until the user quits.++ > import FRP.Helm+ > import qualified FRP.Helm.Window as Window+ >+ > render :: (Int, Int) -> Element+ > render (w, h) = collage w h [filled red $ rect (fromIntegral w) (fromIntegral h)]+ >+ > main :: IO ()+ > main = run $ do+ > dims <- Window.dimensions+ >+ > return $ fmap render dims+ -} run :: SignalGen (Signal Element) -> IO () run gen = SDL.init [SDL.InitVideo] >> requestDimensions 800 600 >> start gen >>= newEngineState >>= run' +{-| A utility function called by 'run' that samples the element+ or quits the entire engine if SDL events say to do so. -} run' :: EngineState -> IO () run' state = do continue <- run'' if continue then smp state >>= render state >> run' state else SDL.quit +{-| A utility function called by 'run\'' that polls all SDL events+ off the stack, returning true if the game should keep running,+ false otherwise. -} run'' :: IO Bool run'' = do event <- SDL.pollEvent@@ -78,9 +106,13 @@ SDL.VideoResize w h -> requestDimensions w h >> run'' _ -> run'' +{-| A utility function that renders a previously sampled element+ using an engine state. -} render :: EngineState -> Element -> IO () render state element = SDL.getVideoSurface >>= render' state element +{-| A utility function called by 'render\'' that does+ the actual heavy lifting. -} render' :: EngineState -> Element -> SDL.Surface -> IO () render' state element screen = do pixels <- SDL.surfaceGetPixels screen@@ -94,6 +126,8 @@ w = SDL.surfaceGetWidth screen h = SDL.surfaceGetHeight screen +{-| A utility function called by 'render\'\'' that is called by Cairo+ when it's ready to do rendering. -} render'' :: Int -> Int -> EngineState -> Element -> Cairo.Render () render'' w h state element = do Cairo.setSourceRGB 0 0 0@@ -102,37 +136,53 @@ renderElement state element -getSurface :: EngineState -> FilePath -> IO Cairo.Surface+{-| A utility function that lazily grabs an image surface from the cache,+ i.e. creating it if it's not already stored in it. -}+getSurface :: EngineState -> FilePath -> IO (Cairo.Surface, Int, Int) getSurface (EngineState { cache }) src = do cached <- Cairo.liftIO (readIORef cache) case Map.lookup src cached of- Just surface -> return surface+ Just surface -> do+ w <- Cairo.imageSurfaceGetWidth surface+ h <- Cairo.imageSurfaceGetHeight surface++ return (surface, w, h) Nothing -> do -- TODO: Use SDL_image to support more formats. I gave up after it was painful -- to convert between the two surface types safely. -- FIXME: Does this throw an error? surface <- Cairo.imageSurfaceCreateFromPNG src-- writeIORef cache (Map.insert src surface cached) >> return surface+ w <- Cairo.imageSurfaceGetWidth surface+ h <- Cairo.imageSurfaceGetHeight surface + writeIORef cache (Map.insert src surface cached) >> return (surface, w, h) +{-| A utility function for rendering a specific element. -} renderElement :: EngineState -> Element -> Cairo.Render () renderElement state (CollageElement _ _ forms) = mapM (renderForm state) forms >> return ()-renderElement state (ImageElement (sx, sy) sw sh src _) = do- surface <- Cairo.liftIO $ getSurface state (normalise src)+renderElement state (ImageElement (sx, sy) sw sh src stretch) = do+ (surface, w, h) <- Cairo.liftIO $ getSurface state (normalise src) Cairo.save Cairo.translate (-fromIntegral sx) (-fromIntegral sy)++ if stretch then+ Cairo.scale (fromIntegral sw / fromIntegral w) (fromIntegral sh / fromIntegral h)+ else+ Cairo.scale 1 1+ Cairo.setSourceSurface surface 0 0 Cairo.translate (fromIntegral sx) (fromIntegral sy) Cairo.rectangle 0 0 (fromIntegral sw) (fromIntegral sh) Cairo.fill Cairo.restore +{-| A utility function that goes into a state of transformation and then pops it when finished. -} withTransform :: Double -> Double -> Double -> Double -> Cairo.Render () -> Cairo.Render () withTransform s t x y f = Cairo.save >> Cairo.scale s s >> Cairo.rotate t >> Cairo.translate x y >> f >> Cairo.restore +{-| A utility function that sets the Cairo line cap based off of our version. -} setLineCap :: LineCap -> Cairo.Render () setLineCap cap = case cap of@@ -140,6 +190,7 @@ Round -> Cairo.setLineCap Cairo.LineCapRound Padded -> Cairo.setLineCap Cairo.LineCapSquare +{-| A utility function that sets the Cairo line style based off of our version. -} setLineJoin :: LineJoin -> Cairo.Render () setLineJoin join = case join of@@ -147,15 +198,21 @@ Sharp lim -> Cairo.setLineJoin Cairo.LineJoinMiter >> Cairo.setMiterLimit lim Clipped -> Cairo.setLineJoin Cairo.LineJoinBevel +{-| A utility function that sets up all the necessary settings with Cairo+ to render with a line style and then strokes afterwards. Assumes+ that all drawing paths have already been setup before being called. -} setLineStyle :: LineStyle -> Cairo.Render () setLineStyle (LineStyle { color = Color r g b a, .. }) = Cairo.setSourceRGBA r g b a >> setLineCap cap >> setLineJoin join >> Cairo.setLineWidth width >> Cairo.setDash dashing dashOffset >> Cairo.stroke +{-| A utility function that sets up all the necessary settings with Cairo+ to render with a fill style and then fills afterwards. Assumes+ that all drawing paths have already been setup before being called. -} setFillStyle :: EngineState -> FillStyle -> Cairo.Render () setFillStyle _ (Solid (Color r g b a)) = Cairo.setSourceRGBA r g b a >> Cairo.fill setFillStyle state (Texture src) = do- surface <- Cairo.liftIO $ getSurface state (normalise src)+ (surface, w, h) <- Cairo.liftIO $ getSurface state (normalise src) Cairo.setSourceSurface surface 0 0 >> Cairo.getSource >>= (flip Cairo.patternSetExtend) Cairo.ExtendRepeat Cairo.fill@@ -168,6 +225,7 @@ Cairo.withRadialPattern sx sy sr ex ey er $ \pattern -> do Cairo.setSource pattern >> mapM (\(o, (Color r g b a)) -> Cairo.patternAddColorStopRGBA pattern o r g b a) points >> Cairo.fill +{-| A utility that renders a form. -} renderForm :: EngineState -> Form -> Cairo.Render () renderForm _ (Form { style = PathForm style p, .. }) = withTransform scalar theta x y $ @@ -176,16 +234,34 @@ where (hx, hy) = head p -renderForm state (Form { style = ShapeForm style shape, .. }) =+renderForm state (Form { style = ShapeForm style (PolygonShape points), .. }) = withTransform scalar theta x y $ do- Cairo.newPath >> Cairo.moveTo hx hy >> mapM (\(x_, y_) -> Cairo.lineTo x_ y_) shape >> Cairo.closePath+ Cairo.newPath >> Cairo.moveTo hx hy >> mapM (\(x_, y_) -> Cairo.lineTo x_ y_) points >> Cairo.closePath case style of Left lineStyle -> setLineStyle lineStyle Right fillStyle -> setFillStyle state fillStyle where- (hx, hy) = head shape+ (hx, hy) = head points++renderForm state (Form { style = ShapeForm style (RectangleShape (w, h)), .. }) =+ withTransform scalar theta x y $ do+ Cairo.rectangle 0 0 w h++ case style of+ Left lineStyle -> setLineStyle lineStyle+ Right fillStyle -> setFillStyle state fillStyle++renderForm state (Form { style = ShapeForm style (ArcShape (cx, cy) a1 a2 r (sx, sy)), .. }) =+ withTransform scalar theta x y $ do+ Cairo.scale sx sy+ Cairo.arc cx cy r a1 a2+ Cairo.scale 1 1++ case style of+ Left lineStyle -> setLineStyle lineStyle+ Right fillStyle -> setFillStyle state fillStyle renderForm state (Form { style = ElementForm element, .. }) = withTransform scalar theta x y $ renderElement state element renderForm state (Form { style = GroupForm m forms, .. }) = withTransform scalar theta x y $ Cairo.setMatrix m >> mapM (renderForm state) forms >> return ()
FRP/Helm/Color.hs view
@@ -1,83 +1,177 @@-module FRP.Helm.Color where+{-| Contains all data structures and functions for composing colors. -}+module FRP.Helm.Color (+ -- * Types+ Color(..),+ Gradient(..),+ -- * Composing+ rgba,+ rgb,+ hsva,+ hsv,+ complement,+ linear,+ radial,+ -- * Constants+ red,+ lime,+ blue,+ yellow,+ cyan,+ magenta,+ black,+ white,+ gray,+ grey,+ maroon,+ navy,+ green,+ teal,+ purple,+ violet,+ forestGreen+) where +{-| A data structure describing a color. It is represented interally as an RGBA+ color, but the utility functions 'hsva', 'hsv', etc. can be used to convert+ from other popular formats to this structure. -} data Color = Color { r :: !Double, g :: !Double, b :: !Double, a :: !Double } --- |Creates an RGB color.+{-| Creates an RGB color. -} rgb :: Double -> Double -> Double -> Color rgb r g b = Color r g b 1 --- |Creates an RGB color, with transparency.+{-| Creates an RGB color, with transparency. -} rgba :: Double -> Double -> Double -> Double -> Color rgba = Color +{-| A bright red color. -} red :: Color red = rgb 1 0 0 +{-| A bright green color. -} lime :: Color lime = rgb 0 1 0 +{-| A bright blue color. -} blue :: Color blue = rgb 0 0 1 +{-| A yellow color, made from combining red and green. -} yellow :: Color yellow = rgb 1 1 0 +{-| A cyan color, combined from bright green and blue. -} cyan :: Color cyan = rgb 0 1 1 +{-| A magenta color, combined from bright red and blue. -} magenta :: Color magenta = rgb 1 0 1 +{-| A black color. -} black :: Color black = rgb 0 0 0 +{-| A white color. -} white :: Color white = rgb 1 1 1 +{-| A gray color, exactly halfway between black and white. -} gray :: Color gray = rgb 0.5 0.5 0.5 +{-| Common alternative spelling of 'gray'. -} grey :: Color grey = gray +{-| A medium red color. -} maroon :: Color maroon = rgb 0.5 0 0 +{-| A medium blue color. -} navy :: Color navy = rgb 0 0 0.5 +{-| A medium green color. -} green :: Color green = rgb 0 0.5 0 +{-| A teal color, combined from medium green and blue. -} teal :: Color teal = rgb 0 0.5 0.5 +{-| A purple color, combined from medium red and blue. -} purple :: Color purple = rgb 0.5 0 0.5 +{-| A violet color. -} violet :: Color violet = rgb 0.923 0.508 0.923 +{-| A dark green color. -} forestGreen :: Color forestGreen = rgb 0.133 0.543 0.133 -{- TODO:-+{-| Calculate a complementary color for a provided color. Useful for outlining+ a filled shape in a color clearly distinguishable from the fill color. -} complement :: Color -> Color+complement (Color r g b a) = hsva (fromIntegral ((round (h + 180) :: Int) `mod` 360)) (s / mx) mx a+ where+ mx = r `max` g `max` b+ mn = r `min` g `min` b+ s = mx - mn+ h | mx == r = (g - b) / s * 60+ | mx == g = (b - r) / s * 60 + 120+ | mx == b = (r - g) / s * 60 + 240+ | otherwise = undefined +{-| Create an RGBA color from HSVA values. -} hsva :: Double -> Double -> Double -> Double -> Color+hsva h s v a+ | h'' == 0 = rgba v t p a+ | h'' == 1 = rgba q v p a+ | h'' == 2 = rgba p v t a+ | h'' == 3 = rgba p q v a+ | h'' == 4 = rgba t p v a+ | h'' == 5 = rgba v p q a+ | otherwise = undefined + where+ h' = h / 60+ h'' = (floor h') `mod` 6 :: Int+ f = h' - fromIntegral h''+ p = v * (1 - s)+ q = v * (1 - f * s)+ t = v * (1 - (1 - f) * s) ++{-| Create an RGB color from HSV values. -} hsv :: Double -> Double -> Double -> Color--}+hsv h s v = hsva h s v 1 +{-| A data structure describing a gradient. There are two types of gradients:+ radial and linear. Radial gradients are based on a set of colors transitioned+ over certain radii in an arc pattern. Linear gradients are a set of colors+ transitioned in a straight line. -} data Gradient = Linear (Double, Double) (Double, Double) [(Double, Color)] | Radial (Double, Double) Double (Double, Double) Double [(Double, Color)] --- |Creates a linear gradient. Takes an +{-| Creates a linear gradient. Takes a starting position, ending position and a list+ of color stops (which are colors combined with a floating value between /0.0/ and /1.0/+ that describes at what step along the line between the starting position+ and ending position the paired color should be transitioned to).++ > linear (0, 0) (100, 100) [(0, black), (1, white)]++ The above example creates a gradient that starts at /(0, 0)/+ and ends at /(100, 100)/. In other words, it's a diagonal gradient, transitioning from the top-left+ to the bottom-right. The provided color stops result in the gradient transitioning from+ black to white.+ -} linear :: (Double, Double) -> (Double, Double) -> [(Double, Color)] -> Gradient linear = Linear --- |Creates a radial gradient.+{-| Creates a radial gradient. Takes a starting position and radius, ending position and radius+ and a list of color stops. See the document for 'linear' for more information on color stops. -} radial :: (Double, Double) -> Double -> (Double, Double) -> Double -> [(Double, Color)] -> Gradient radial = Radial
FRP/Helm/Graphics.hs view
@@ -1,17 +1,26 @@+{-| Contains all the data structures and functions for composing+ and rendering graphics. -} module FRP.Helm.Graphics (+ -- * Types Element(..),- image,- croppedImage, Form(..),+ FormStyle(..), FillStyle(..), LineCap(..), LineJoin(..), LineStyle(..),+ Path,+ Shape(..),+ -- * Elements+ image,+ fittedImage,+ croppedImage,+ collage,+ -- * Styles & Forms defaultLine, solid, dashed, dotted,- FormStyle(..), filled, textured, gradient,@@ -19,18 +28,19 @@ traced, sprite, toForm,+ -- * Grouping group, groupTransform,+ -- * Transforming rotate, scale, move, moveX, moveY,- collage,- Path,+ -- * Paths path, segment,- Shape,+ -- * Shapes polygon, rect, square,@@ -42,6 +52,13 @@ import FRP.Helm.Color as Color import Graphics.Rendering.Cairo.Matrix (Matrix, identity) +{-| A data structure describing something that can be rendered+ to the screen. Elements are the most important structure+ in Helm. Games essentially feed the engine a stream+ of elements which are then rendered directly to the screen.+ The usual way to render art in a Helm game is to call+ off to the 'collage' function, which essentially+ renders a collection of forms together. -} data Element = CollageElement Int Int [Form] | ImageElement (Int, Int) Int Int FilePath Bool @@ -51,19 +68,21 @@ image :: Int -> Int -> FilePath -> Element image w h src = ImageElement (0, 0) w h src True -{- TODO: {-| Create an element from an image with a given width, height and image file path. If the image dimensions are not the same as given, then it will only use the relevant pixels- (i.e. cut out the given width instead of scaling). If the given dimensions are bigger than+ (i.e. cut out the given dimensions instead of scaling). If the given dimensions are bigger than the actual image, than irrelevant pixels are ignored. -} fittedImage :: Int -> Int -> FilePath -> Element-fittedImage w h src = ImageElement (0, 0) w h src False -}+fittedImage w h src = ImageElement (0, 0) w h src False {-| Create an element from an image by cropping it with a certain position, width, height and image file path. This can be used to divide a single image up into smaller ones. -} croppedImage :: (Int, Int) -> Int -> Int -> FilePath -> Element croppedImage pos w h src = ImageElement pos w h src False +{-| A data structure describing a form. A form is essentially a notion of a transformed+ graphic, whether it be an element or shape. See 'FormStyle' for an insight+ into what sort of graphics can be wrapped in a form. -} data Form = Form { theta :: Double, scalar :: Double,@@ -71,9 +90,19 @@ y :: Double, style :: FormStyle }++{-| A data structure describing how a shape or path looks when filled. -} data FillStyle = Solid Color | Texture String | Gradient Gradient++{-| A data structure describing the shape of the ends of a line. -} data LineCap = Flat | Round | Padded++{-| A data structure describing the shape of the join of a line, i.e.+ where separate line segments join. The 'Sharp' variant takes+ an argument to limit the length of the join. -} data LineJoin = Smooth | Sharp Double | Clipped++{-| A data structure describing how a shape or path looks when stroked. -} data LineStyle = LineStyle { color :: Color, width :: Double,@@ -95,46 +124,50 @@ dashOffset = 0 } --- |Create a solid line style with a color.+{-| Create a solid line style with a color. -} solid :: Color -> LineStyle solid color = defaultLine { color = color } --- |Create a dashed line style with a color.+{-| Create a dashed line style with a color. -} dashed :: Color -> LineStyle dashed color = defaultLine { color = color, dashing = [8, 4] } --- |Create a dotted line style with a color.+{-| Create a dotted line style with a color. -} dotted :: Color -> LineStyle dotted color = defaultLine { color = color, dashing = [3, 3] } +{-| A data structure describing a few ways that graphics that can be wrapped in a form+ and hence transformed. -} data FormStyle = PathForm LineStyle Path | ShapeForm (Either LineStyle FillStyle) Shape | ElementForm Element | GroupForm Matrix [Form] +{-| Utility function for creating a form. -} form :: FormStyle -> Form form style = Form { theta = 0, scalar = 1, x = 0, y = 0, style = style } +{-| Utility function for creating a filled form from a fill style and shape. -} fill :: FillStyle -> Shape -> Form fill style shape = form (ShapeForm (Right style) shape) --- |Creates a form from a shape by filling it with a specific color.+{-| Creates a form from a shape by filling it with a specific color. -} filled :: Color -> Shape -> Form filled color shape = fill (Solid color) shape --- |Creates a form from a shape with a tiled texture and image file path.+{-| Creates a form from a shape with a tiled texture and image file path. -} textured :: String -> Shape -> Form textured src shape = fill (Texture src) shape --- |Creates a form from a shape filled with a gradient.+{-| Creates a form from a shape filled with a gradient. -} gradient :: Gradient -> Shape -> Form gradient grad shape = fill (Gradient grad) shape --- |Creates a form from a shape by outlining it with a specific line style.+{-| Creates a form from a shape by outlining it with a specific line style. -} outlined :: LineStyle -> Shape -> Form outlined style shape = form (ShapeForm (Left style) shape) --- |Creates a form from a path by tracing it with a specific line style.+{-| Creates a form from a path by tracing it with a specific line style. -} traced :: LineStyle -> Path -> Form traced style p = form (PathForm style p) @@ -143,88 +176,86 @@ sprite :: Int -> Int -> (Int, Int) -> FilePath -> Form sprite w h pos src = form (ElementForm (ImageElement pos w h src False)) --- |Creates a form from an element.+{-| Creates a form from an element. -} toForm :: Element -> Form toForm element = form (ElementForm element) --- |Groups a collection of forms into a single one.+{-| Groups a collection of forms into a single one. -} group :: [Form] -> Form group forms = form (GroupForm identity forms) --- |Groups a collection of forms into a single one, also applying a matrix transformation.+{-| Groups a collection of forms into a single one, also applying a matrix transformation. -} groupTransform :: Matrix -> [Form] -> Form groupTransform matrix forms = form (GroupForm matrix forms) --- |Rotates a form by an amount (in radians).+{-| Rotates a form by an amount (in radians). -} rotate :: Double -> Form -> Form rotate t f = f { theta = t + theta f } --- |Scales a form by an amount, e.g. scaling by 2 will double the size.+{-| Scales a form by an amount, e.g. scaling by /2.0/ will double the size. -} scale :: Double -> Form -> Form scale n f = f { scalar = n + scalar f } --- |Moves a form relative to its current position.+{-| Moves a form relative to its current position. -} move :: (Double, Double) -> Form -> Form move (rx, ry) f = f { x = rx + x f, y = ry + y f } --- |Moves a form's x-coordinate relative to its current position.+{-| Moves a form's x-coordinate relative to its current position. -} moveX :: Double -> Form -> Form moveX x f = move (x, 0) f --- |Moves a form's y-coordinate relative to its current position.+{-| Moves a form's y-coordinate relative to its current position. -} moveY :: Double -> Form -> Form moveY y f = move (0, y) f -{-| Create an element from a collection of forms.- Can be used to directly render a collection of forms. -}+{-| Create an element from a collection of forms, with width and height arguments.+ Can be used to directly render a collection of forms.++ > collage 800 600 [move (100, 100) $ filled red $ square 100,+ > move (100, 100) $ outlined (solid white) $ circle 50]+ -} collage :: Int -> Int -> [Form] -> Element collage w h forms = CollageElement w h forms +{-| A data type made up a collection of points that form a path when joined. -} type Path = [(Double, Double)] --- |Creates a path for a collection of points.+{-| Creates a path for a collection of points. -} path :: [(Double, Double)] -> Path path points = points --- |Creates a path from a line segment, i.e. a start and end point.+{-| Creates a path from a line segment, i.e. a start and end point. -} segment :: (Double, Double) -> (Double, Double) -> Path-segment p1 p2 = [p1,p2]+segment p1 p2 = [p1, p2] -type Shape = [(Double, Double)]+{-| A data structure describing a some sort of graphically representable object,+ such as a polygon formed from a set of points or a rectangle. -}+data Shape = PolygonShape Path | RectangleShape (Double, Double) | ArcShape (Double, Double) Double Double Double (Double, Double) --- |Creates a shape from a set of points.-polygon :: [(Double, Double)] -> Shape-polygon points = points+{-| Creates a shape from a path (a set of points). -}+polygon :: Path -> Shape+polygon points = PolygonShape points --- |Creates a rectangular shape with a specific width and height.+{-| Creates a rectangular shape with a width and height. -} rect :: Double -> Double -> Shape-rect w h = [(-hw, -hh), (-hw, hh), (hw, hh), (hw, -hh)]- where- hw = w / 2- hh = h / 2+rect w h = RectangleShape (w, h) --- |Creates a square shape with a specific side length.+{-| Creates a square shape with a side length. -} square :: Double -> Shape square n = rect n n --- |Creates an oval shape with a specific width and height.+{-| Creates an oval shape with a width and height. -} oval :: Double -> Double -> Shape-oval w h = map (\i -> (hw * cos (t * i), hh * sin (t * i))) [0 .. n - 1]- where- n = 50- t = 2 * pi / n- hw = w / 2- hh = h / 2+oval w h = ArcShape (0, 0) 0 (2 * pi) 1 (w / 2, h / 2) --- |Creates an oval shape with a specific radius.-{- TODO: Make a separate variant of a shape that is based on an arc.- as this sort of thing is going to be pretty unaccurate and slower. -}+{-| Creates a circle shape with a radius. -} circle :: Double -> Shape-circle r = oval (2 * r) (2 * r)+circle r = ArcShape (0, 0) 0 (2 * pi) r (1, 1) --- |Creates a generic n-sided polygon (e.g. octagon) with a specific amount of sides and radius.+{-| Creates a generic n-sided polygon (e.g. octagon, pentagon, etc) with+ an amount of sides and radius. -} ngon :: Int -> Double -> Shape-ngon n r = map (\i -> (r * cos (t * i), r * sin (t * i))) [0 .. fromIntegral (n - 1)]+ngon n r = PolygonShape (map (\i -> (r * cos (t * i), r * sin (t * i))) [0 .. fromIntegral (n - 1)]) where m = fromIntegral n t = 2 * pi / m
FRP/Helm/Keyboard.hs view
@@ -1,11 +1,12 @@+{-| Contains signals that sample input from the keyboard. -} module FRP.Helm.Keyboard (- shift,- ctrl,- enter,+ -- * Types Key(..),- space,- arrows,- wasd+ -- * Key State+ shift, ctrl, enter,+ space, isDown, keysDown,+ -- * Directions+ arrows, wasd ) where import Control.Applicative@@ -14,18 +15,19 @@ import Foreign.C.Types import FRP.Elerea.Simple import qualified Graphics.UI.SDL as SDL-import qualified Graphics.UI.SDL.Utilities as Utilities --- The SDL bindings for Haskell don't wrap this, so we have to use the FFI ourselves.+{-| The SDL bindings for Haskell don't wrap this, so we have to use the FFI ourselves. -} foreign import ccall unsafe "SDL_GetKeyState" sdlGetKeyState :: Ptr CInt -> IO (Ptr Word8) --- Based on http://coderepos.org/share/browser/lang/haskell/nario/Main.hs?rev=22646#L49-getKeyState :: IO [SDL.SDLKey]+{-| A utility function for getting a list of SDL keys currently pressed.+ Based on <http://coderepos.org/share/browser/lang/haskell/nario/Main.hs?rev=22646#L49>. -}+getKeyState :: IO [Int] getKeyState = alloca $ \numkeysPtr -> do keysPtr <- sdlGetKeyState numkeysPtr numkeys <- peek numkeysPtr- (map Utilities.toEnum . map fromIntegral . findIndices (== 1)) <$> peekArray (fromIntegral numkeys) keysPtr+ (map fromIntegral . findIndices (== 1)) <$> peekArray (fromIntegral numkeys) keysPtr +{-| A data structure describing a physical key on a keyboard. -} data Key = BackspaceKey | TabKey | ClearKey | EnterKey | PauseKey | EscapeKey | SpaceKey | ExclaimKey | QuotedBlKey | HashKey | DollarKey | AmpersandKey | QuoteKey | LeftParenKey | RightParenKey | AsteriskKey | PlusKey | CommaKey |@@ -34,187 +36,325 @@ Num9Key | ColonKey | SemicolonKey | LessKey | EqualsKey | GreaterKey | QuestionKey | AtKey | LeftBracketKey | BackslashKey | RightBracketKey | CaretKey | UnderscoreKey | BackquoteKey | AKey | BKey | CKey | DKey |- EKey | FKey | GKey | HKey | IKey | JKey |+ EKey | FKey | GKey | HKey | IKey | JKey | KKey | LKey | MKey | NKey | OKey | PKey | QKey | RKey | SKey | TKey | UKey | VKey | WKey |- XKey | YKey | ZKey | DeleteKey | Keypad0Key | Keypad1Key |- Keypad2Key | Keypad3Key | Keypad4Key | Keypad5Key | Keypad6Key | Keypad7Key |- Keypad8Key | Keypad9Key | KeypadPeriodKey | KeypadDivideKey | KeypadMultiplyKey | KeypadMinusKey |+ XKey | YKey | ZKey | DeleteKey | KeypadNum0Key | KeypadNum1Key |+ KeypadNum2Key | KeypadNum3Key | KeypadNum4Key | KeypadNum5Key | KeypadNum6Key | KeypadNum7Key |+ KeypadNum8Key | KeypadNum9Key | KeypadPeriodKey | KeypadDivideKey | KeypadMultiplyKey | KeypadMinusKey | KeypadPlusKey | KeypadEnterKey | KeypadEqualsKey | UpKey | DownKey | RightKey | LeftKey | InsertKey | HomeKey | EndKey | PageUpKey | PageDownKey | F1Key | F2Key | F3Key | F4Key | F5Key | F6Key | F7Key | F8Key | F9Key | F10Key | F11Key | F12Key | F13Key | F14Key | F15Key | NumLockKey | CapsLockKey | ScrollLockKey | RShiftKey | LShiftKey | RCtrlKey | LCtrlKey | RAltKey | LAltKey |- RMetaKey | LMetaKey | RSuperKey | LSuperKey | ComposeKey | HelpKey |+ RMetaKey | LMetaKey | RSuperKey | LSuperKey | ModeKey | ComposeKey | HelpKey | PrintKey | SysReqKey | BreakKey | MenuKey | PowerKey | EuroKey | UndoKey -mapKey :: Key -> SDL.SDLKey-mapKey k =- case k of- BackspaceKey -> SDL.SDLK_BACKSPACE- TabKey -> SDL.SDLK_TAB- ClearKey -> SDL.SDLK_CLEAR- EnterKey -> SDL.SDLK_RETURN- PauseKey -> SDL.SDLK_PAUSE- EscapeKey -> SDL.SDLK_ESCAPE- SpaceKey -> SDL.SDLK_SPACE- ExclaimKey -> SDL.SDLK_EXCLAIM- QuotedBlKey -> SDL.SDLK_QUOTEDBL- HashKey -> SDL.SDLK_HASH- DollarKey -> SDL.SDLK_DOLLAR- AmpersandKey -> SDL.SDLK_AMPERSAND- QuoteKey -> SDL.SDLK_QUOTE- LeftParenKey -> SDL.SDLK_LEFTPAREN- RightParenKey -> SDL.SDLK_RIGHTPAREN- AsteriskKey -> SDL.SDLK_ASTERISK- PlusKey -> SDL.SDLK_PLUS- CommaKey -> SDL.SDLK_COMMA- MinusKey -> SDL.SDLK_MINUS- PeriodKey -> SDL.SDLK_PERIOD- SlashKey -> SDL.SDLK_SLASH- Num0Key -> SDL.SDLK_0- Num1Key -> SDL.SDLK_1- Num2Key -> SDL.SDLK_2- Num3Key -> SDL.SDLK_3- Num4Key -> SDL.SDLK_4- Num5Key -> SDL.SDLK_5- Num6Key -> SDL.SDLK_6- Num7Key -> SDL.SDLK_7- Num8Key -> SDL.SDLK_8- Num9Key -> SDL.SDLK_9- ColonKey -> SDL.SDLK_COLON- SemicolonKey -> SDL.SDLK_SEMICOLON- LessKey -> SDL.SDLK_LESS- EqualsKey -> SDL.SDLK_EQUALS- GreaterKey -> SDL.SDLK_GREATER- QuestionKey -> SDL.SDLK_QUESTION- AtKey -> SDL.SDLK_AT- LeftBracketKey -> SDL.SDLK_LEFTBRACKET- BackslashKey -> SDL.SDLK_BACKSLASH- RightBracketKey -> SDL.SDLK_RIGHTBRACKET- CaretKey -> SDL.SDLK_CARET- UnderscoreKey -> SDL.SDLK_UNDERSCORE- BackquoteKey -> SDL.SDLK_BACKQUOTE- AKey -> SDL.SDLK_a- BKey -> SDL.SDLK_b- CKey -> SDL.SDLK_c- DKey -> SDL.SDLK_d- EKey -> SDL.SDLK_e- FKey -> SDL.SDLK_f- GKey -> SDL.SDLK_g- HKey -> SDL.SDLK_h- IKey -> SDL.SDLK_i- JKey -> SDL.SDLK_j- LKey -> SDL.SDLK_l- MKey -> SDL.SDLK_m- NKey -> SDL.SDLK_n- OKey -> SDL.SDLK_o- PKey -> SDL.SDLK_p- QKey -> SDL.SDLK_q- RKey -> SDL.SDLK_r- SKey -> SDL.SDLK_s- TKey -> SDL.SDLK_t- UKey -> SDL.SDLK_u- VKey -> SDL.SDLK_v- WKey -> SDL.SDLK_w- XKey -> SDL.SDLK_x- YKey -> SDL.SDLK_y- ZKey -> SDL.SDLK_z- DeleteKey -> SDL.SDLK_DELETE- Keypad0Key -> SDL.SDLK_KP0- Keypad1Key -> SDL.SDLK_KP1- Keypad2Key -> SDL.SDLK_KP2- Keypad3Key -> SDL.SDLK_KP3- Keypad4Key -> SDL.SDLK_KP4- Keypad5Key -> SDL.SDLK_KP5- Keypad6Key -> SDL.SDLK_KP6- Keypad7Key -> SDL.SDLK_KP7- Keypad8Key -> SDL.SDLK_KP8- Keypad9Key -> SDL.SDLK_KP9- KeypadPeriodKey -> SDL.SDLK_KP_PERIOD- KeypadDivideKey -> SDL.SDLK_KP_DIVIDE- KeypadMultiplyKey -> SDL.SDLK_KP_MULTIPLY- KeypadMinusKey -> SDL.SDLK_KP_MINUS- KeypadPlusKey -> SDL.SDLK_KP_PLUS- KeypadEnterKey -> SDL.SDLK_KP_ENTER- KeypadEqualsKey -> SDL.SDLK_KP_EQUALS- UpKey -> SDL.SDLK_UP- DownKey -> SDL.SDLK_DOWN- RightKey -> SDL.SDLK_RIGHT- LeftKey -> SDL.SDLK_LEFT- InsertKey -> SDL.SDLK_INSERT- HomeKey -> SDL.SDLK_HOME- EndKey -> SDL.SDLK_END- PageUpKey -> SDL.SDLK_PAGEUP- PageDownKey -> SDL.SDLK_PAGEDOWN- F1Key -> SDL.SDLK_F1- F2Key -> SDL.SDLK_F2- F3Key -> SDL.SDLK_F3- F4Key -> SDL.SDLK_F4- F5Key -> SDL.SDLK_F5- F6Key -> SDL.SDLK_F6- F7Key -> SDL.SDLK_F7- F8Key -> SDL.SDLK_F8- F9Key -> SDL.SDLK_F9- F10Key -> SDL.SDLK_F10- F11Key -> SDL.SDLK_F11- F12Key -> SDL.SDLK_F12- F13Key -> SDL.SDLK_F13- F14Key -> SDL.SDLK_F14- F15Key -> SDL.SDLK_F15- NumLockKey -> SDL.SDLK_NUMLOCK- CapsLockKey -> SDL.SDLK_CAPSLOCK- ScrollLockKey -> SDL.SDLK_SCROLLOCK- RShiftKey -> SDL.SDLK_RSHIFT- LShiftKey -> SDL.SDLK_LSHIFT- RCtrlKey -> SDL.SDLK_RCTRL- LCtrlKey -> SDL.SDLK_LCTRL- RAltKey -> SDL.SDLK_RALT- LAltKey -> SDL.SDLK_LALT- RMetaKey -> SDL.SDLK_RMETA- LMetaKey -> SDL.SDLK_LMETA- RSuperKey -> SDL.SDLK_RSUPER- LSuperKey -> SDL.SDLK_LSUPER- ComposeKey -> SDL.SDLK_COMPOSE- HelpKey -> SDL.SDLK_HELP- PrintKey -> SDL.SDLK_PRINT- SysReqKey -> SDL.SDLK_SYSREQ- BreakKey -> SDL.SDLK_BREAK- MenuKey -> SDL.SDLK_MENU- PowerKey -> SDL.SDLK_POWER- EuroKey -> SDL.SDLK_EURO- UndoKey -> SDL.SDLK_UNDO+{- All integer values of this enum are equivalent to the SDL key enum. -}+instance Enum Key where+ fromEnum BackspaceKey = 8+ fromEnum TabKey = 9+ fromEnum ClearKey = 12+ fromEnum EnterKey = 13+ fromEnum PauseKey = 19+ fromEnum EscapeKey = 27+ fromEnum SpaceKey = 32+ fromEnum ExclaimKey = 33+ fromEnum QuotedBlKey = 34+ fromEnum HashKey = 35+ fromEnum DollarKey = 36+ fromEnum AmpersandKey = 38+ fromEnum QuoteKey = 39+ fromEnum LeftParenKey = 40+ fromEnum RightParenKey = 41+ fromEnum AsteriskKey = 42+ fromEnum PlusKey = 43+ fromEnum CommaKey = 44+ fromEnum MinusKey = 45+ fromEnum PeriodKey = 46+ fromEnum SlashKey = 47+ fromEnum Num0Key = 48+ fromEnum Num1Key = 49+ fromEnum Num2Key = 50+ fromEnum Num3Key = 51+ fromEnum Num4Key = 52+ fromEnum Num5Key = 53+ fromEnum Num6Key = 54+ fromEnum Num7Key = 55+ fromEnum Num8Key = 56+ fromEnum Num9Key = 57+ fromEnum ColonKey = 58+ fromEnum SemicolonKey = 59+ fromEnum LessKey = 60+ fromEnum EqualsKey = 61+ fromEnum GreaterKey = 62+ fromEnum QuestionKey = 63+ fromEnum AtKey = 64+ fromEnum LeftBracketKey = 91+ fromEnum BackslashKey = 92+ fromEnum RightBracketKey = 93+ fromEnum CaretKey = 94+ fromEnum UnderscoreKey = 95+ fromEnum BackquoteKey = 96+ fromEnum AKey = 97+ fromEnum BKey = 98+ fromEnum CKey = 99+ fromEnum DKey = 100+ fromEnum EKey = 101+ fromEnum FKey = 102+ fromEnum GKey = 103+ fromEnum HKey = 104+ fromEnum IKey = 105+ fromEnum JKey = 106+ fromEnum KKey = 107+ fromEnum LKey = 108+ fromEnum MKey = 109+ fromEnum NKey = 110+ fromEnum OKey = 111+ fromEnum PKey = 112+ fromEnum QKey = 113+ fromEnum RKey = 114+ fromEnum SKey = 115+ fromEnum TKey = 116+ fromEnum UKey = 117+ fromEnum VKey = 118+ fromEnum WKey = 119+ fromEnum XKey = 120+ fromEnum YKey = 121+ fromEnum ZKey = 122+ fromEnum DeleteKey = 127+ fromEnum KeypadNum0Key = 256+ fromEnum KeypadNum1Key = 257+ fromEnum KeypadNum2Key = 258+ fromEnum KeypadNum3Key = 259+ fromEnum KeypadNum4Key = 260+ fromEnum KeypadNum5Key = 261+ fromEnum KeypadNum6Key = 262+ fromEnum KeypadNum7Key = 263+ fromEnum KeypadNum8Key = 264+ fromEnum KeypadNum9Key = 265+ fromEnum KeypadPeriodKey = 266+ fromEnum KeypadDivideKey = 267+ fromEnum KeypadMultiplyKey = 268+ fromEnum KeypadMinusKey = 269+ fromEnum KeypadPlusKey = 270+ fromEnum KeypadEnterKey = 271+ fromEnum KeypadEqualsKey = 272+ fromEnum UpKey = 273+ fromEnum DownKey = 274+ fromEnum RightKey = 275+ fromEnum LeftKey = 276+ fromEnum InsertKey = 277+ fromEnum HomeKey = 278+ fromEnum EndKey = 279+ fromEnum PageUpKey = 280+ fromEnum PageDownKey = 281+ fromEnum F1Key = 282+ fromEnum F2Key = 283+ fromEnum F3Key = 284+ fromEnum F4Key = 285+ fromEnum F5Key = 286+ fromEnum F6Key = 287+ fromEnum F7Key = 288+ fromEnum F8Key = 289+ fromEnum F9Key = 290+ fromEnum F10Key = 291+ fromEnum F11Key = 292+ fromEnum F12Key = 293+ fromEnum F13Key = 294+ fromEnum F14Key = 295+ fromEnum F15Key = 296+ fromEnum NumLockKey = 300+ fromEnum CapsLockKey = 301+ fromEnum ScrollLockKey = 302+ fromEnum RShiftKey = 303+ fromEnum LShiftKey = 304+ fromEnum RCtrlKey = 305+ fromEnum LCtrlKey = 306+ fromEnum RAltKey = 307+ fromEnum LAltKey = 308+ fromEnum RMetaKey = 309+ fromEnum LMetaKey = 310+ fromEnum LSuperKey = 311+ fromEnum RSuperKey = 312+ fromEnum ModeKey = 313+ fromEnum ComposeKey = 314+ fromEnum HelpKey = 315+ fromEnum PrintKey = 316+ fromEnum SysReqKey = 317+ fromEnum BreakKey = 318+ fromEnum MenuKey = 319+ fromEnum PowerKey = 320+ fromEnum EuroKey = 321+ fromEnum UndoKey = 322 --- |Whether either shift key is pressed.+ toEnum 8 = BackspaceKey+ toEnum 9 = TabKey+ toEnum 12 = ClearKey+ toEnum 13 = EnterKey+ toEnum 19 = PauseKey+ toEnum 27 = EscapeKey+ toEnum 32 = SpaceKey+ toEnum 33 = ExclaimKey+ toEnum 34 = QuotedBlKey+ toEnum 35 = HashKey+ toEnum 36 = DollarKey+ toEnum 38 = AmpersandKey+ toEnum 39 = QuoteKey+ toEnum 40 = LeftParenKey+ toEnum 41 = RightParenKey+ toEnum 42 = AsteriskKey+ toEnum 43 = PlusKey+ toEnum 44 = CommaKey+ toEnum 45 = MinusKey+ toEnum 46 = PeriodKey+ toEnum 47 = SlashKey+ toEnum 48 = Num0Key+ toEnum 49 = Num1Key+ toEnum 50 = Num2Key+ toEnum 51 = Num3Key+ toEnum 52 = Num4Key+ toEnum 53 = Num5Key+ toEnum 54 = Num6Key+ toEnum 55 = Num7Key+ toEnum 56 = Num8Key+ toEnum 57 = Num9Key+ toEnum 58 = ColonKey+ toEnum 59 = SemicolonKey+ toEnum 60 = LessKey+ toEnum 61 = EqualsKey+ toEnum 62 = GreaterKey+ toEnum 63 = QuestionKey+ toEnum 64 = AtKey+ toEnum 91 = LeftBracketKey+ toEnum 92 = BackslashKey+ toEnum 93 = RightBracketKey+ toEnum 94 = CaretKey+ toEnum 95 = UnderscoreKey+ toEnum 96 = BackquoteKey+ toEnum 97 = AKey+ toEnum 98 = BKey+ toEnum 99 = CKey+ toEnum 100 = DKey+ toEnum 101 = EKey+ toEnum 102 = FKey+ toEnum 103 = GKey+ toEnum 104 = HKey+ toEnum 105 = IKey+ toEnum 106 = JKey+ toEnum 107 = KKey+ toEnum 108 = LKey+ toEnum 109 = MKey+ toEnum 110 = NKey+ toEnum 111 = OKey+ toEnum 112 = PKey+ toEnum 113 = QKey+ toEnum 114 = RKey+ toEnum 115 = SKey+ toEnum 116 = TKey+ toEnum 117 = UKey+ toEnum 118 = VKey+ toEnum 119 = WKey+ toEnum 120 = XKey+ toEnum 121 = YKey+ toEnum 122 = ZKey+ toEnum 127 = DeleteKey+ toEnum 256 = KeypadNum0Key+ toEnum 257 = KeypadNum1Key+ toEnum 258 = KeypadNum2Key+ toEnum 259 = KeypadNum3Key+ toEnum 260 = KeypadNum4Key+ toEnum 261 = KeypadNum5Key+ toEnum 262 = KeypadNum6Key+ toEnum 263 = KeypadNum7Key+ toEnum 264 = KeypadNum8Key+ toEnum 265 = KeypadNum9Key+ toEnum 266 = KeypadPeriodKey+ toEnum 267 = KeypadDivideKey+ toEnum 268 = KeypadMultiplyKey+ toEnum 269 = KeypadMinusKey+ toEnum 270 = KeypadPlusKey+ toEnum 271 = KeypadEnterKey+ toEnum 272 = KeypadEqualsKey+ toEnum 273 = UpKey+ toEnum 274 = DownKey+ toEnum 275 = RightKey+ toEnum 276 = LeftKey+ toEnum 277 = InsertKey+ toEnum 278 = HomeKey+ toEnum 279 = EndKey+ toEnum 280 = PageUpKey+ toEnum 281 = PageDownKey+ toEnum 282 = F1Key+ toEnum 283 = F2Key+ toEnum 284 = F3Key+ toEnum 285 = F4Key+ toEnum 286 = F5Key+ toEnum 287 = F6Key+ toEnum 288 = F7Key+ toEnum 289 = F8Key+ toEnum 290 = F9Key+ toEnum 291 = F10Key+ toEnum 292 = F11Key+ toEnum 293 = F12Key+ toEnum 294 = F13Key+ toEnum 295 = F14Key+ toEnum 296 = F15Key+ toEnum 300 = NumLockKey+ toEnum 301 = CapsLockKey+ toEnum 302 = ScrollLockKey+ toEnum 303 = RShiftKey+ toEnum 304 = LShiftKey+ toEnum 305 = RCtrlKey+ toEnum 306 = LCtrlKey+ toEnum 307 = RAltKey+ toEnum 308 = LAltKey+ toEnum 309 = RMetaKey+ toEnum 310 = LMetaKey+ toEnum 311 = LSuperKey+ toEnum 312 = RSuperKey+ toEnum 313 = ModeKey+ toEnum 314 = ComposeKey+ toEnum 315 = HelpKey+ toEnum 316 = PrintKey+ toEnum 317 = SysReqKey+ toEnum 318 = BreakKey+ toEnum 319 = MenuKey+ toEnum 320 = PowerKey+ toEnum 321 = EuroKey+ toEnum 322 = UndoKey+ toEnum _ = error "FRP.Helm.Keyboard.Key.toEnum: bad argument"++{-| Whether either shift key is pressed. -} shift :: SignalGen (Signal Bool) shift = effectful $ (elem SDL.KeyModShift) <$> SDL.getModState --- |Whether either control key is pressed.+{-| Whether either control key is pressed. -} ctrl :: SignalGen (Signal Bool) ctrl = effectful $ (elem SDL.KeyModCtrl) <$> SDL.getModState --- |Whether a specific key is pressed.+{-| Whether a key is pressed. -} isDown :: Key -> SignalGen (Signal Bool)-isDown k = effectful $ (elem (mapKey k)) <$> getKeyState+isDown k = effectful $ (elem $ fromEnum k) <$> getKeyState --- |Whether the shift key is pressed.+{-| Whether the enter (a.k.a. return) key is pressed. -} enter :: SignalGen (Signal Bool) enter = isDown EnterKey --- |Whether the space key is pressed.+{-| Whether the space key is pressed. -} space :: SignalGen (Signal Bool) space = isDown SpaceKey -{- TODO:+{-| A list of keys that are currently being pressed. -} keysDown :: SignalGen (Signal [Key])--}+keysDown = effectful $ (map toEnum) <$> getKeyState -{-| A unit vector combined from the arrow keys. When no keys are being pressed- this signal samples to (0, 0), otherwise it samples to a specific direction- based on which keys are pressed. For example, pressing the left key results- in (-1, 0), the down key (0, 1), etc. -}+{-| A directional tuple combined from the arrow keys. When none of the arrow keys+ are being pressed this signal samples to /(0, 0)/, otherwise it samples to a+ direction based on which keys are pressed. For example, pressing the left key+ results in /(-1, 0)/, the down key /(0, 1)/, up and right /(1, -1)/, etc. -} arrows :: SignalGen (Signal (Int, Int)) arrows = do up <- isDown UpKey@@ -224,10 +364,11 @@ return $ arrows' <$> up <*> left <*> down <*> right +{-| A utility function for setting up a vector signal from directional keys. -} arrows' :: Bool -> Bool -> Bool -> Bool -> (Int, Int) arrows' u l d r = (-1 * fromEnum l + 1 * fromEnum r, -1 * fromEnum u + 1 * fromEnum d) --- |Similar to the 'arrows' signal, but uses the W, A, S and D keys instead.+{-| Similar to the 'arrows' signal, but uses the popular WASD movement controls instead. -} wasd :: SignalGen (Signal (Int, Int)) wasd = do w <- isDown WKey
FRP/Helm/Mouse.hs view
@@ -1,24 +1,33 @@-module FRP.Helm.Mouse (position, x, y, isDown, Mouse(..)) where+{-| Contains signals that sample input from the mouse. -}+module FRP.Helm.Mouse (+ -- * Types+ Mouse(..),+ -- * Position+ isDown,+ -- * Mouse State+ position, x, y+) where import Control.Applicative import FRP.Elerea.Simple import qualified Graphics.UI.SDL as SDL +{-| A data structure describing a button on a mouse. -} data Mouse = LeftMouse | MiddleMouse | RightMouse --- |The current mouse position.+{-| The current position of the mouse. -} position :: SignalGen (Signal (Int, Int)) position = effectful $ (\(x_, y_, _) -> (x_, y_)) <$> SDL.getMouseState --- |The current x-coordinate of the mouse.+{-| The current x-coordinate of the mouse. -} x :: SignalGen (Signal Int) x = effectful $ (\(x_, _, _) -> x_) <$> SDL.getMouseState --- |The current y-coordinate of the mouse.+{-| The current y-coordinate of the mouse. -} y :: SignalGen (Signal Int) y = effectful $ (\(_, y_, _) -> y_) <$> SDL.getMouseState -+{-| Maps our mouse type into SDL's one. -} mapMouse :: Mouse -> SDL.MouseButton mapMouse m = case m of@@ -30,7 +39,3 @@ True if the mouse is down, false otherwise. -} isDown :: Mouse -> SignalGen (Signal Bool) isDown m = effectful $ (\(_, _, b_) -> elem (mapMouse m) b_) <$> SDL.getMouseState--{- TODO:-isClicked :: SignalGen (Signal Bool)- -}
FRP/Helm/Window.hs view
@@ -1,4 +1,8 @@-module FRP.Helm.Window (dimensions, width, height) where+{-| Contains signals that sample input from the game window. -}+module FRP.Helm.Window (+ -- * Dimensions+ dimensions, width, height+) where import Control.Applicative import FRP.Elerea.Simple
helm.cabal view
@@ -1,5 +1,5 @@ name: helm-version: 0.1.0+version: 0.2.0 synopsis: A functionally reactive game engine. description: A functionally reactive game engine, with headgear to protect you from the headache of game development provided.