packages feed

clutterhs-0.1: Graphics/UI/Clutter/Path.chs

-- -*-haskell-*-
--  Clutter Path
--
--  Author : Matthew Arsenault
--
--  Created: 2 Oct 2009
--
--  Copyright (C) 2009 Matthew Arsenault
--
--  This library is free software; you can redistribute it and/or
--  modify it under the terms of the GNU Lesser General Public
--  License as published by the Free Software Foundation; either
--  version 3 of the License, or (at your option) any later version.
--
--  This library is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
--  Lesser General Public License for more details.
--
{-# LANGUAGE ForeignFunctionInterface #-}

#include <clutter/clutter.h>

{# context lib="clutter" prefix="clutter" #}

-- | Path — An object describing a path with straight lines and Bezier curves.
module Graphics.UI.Clutter.Path (
-- * Detail
-- | A 'Path' contains a description of a path
-- consisting of straight lines and bezier curves. This can be used in
-- a 'BehaviourPath' to animate an actor moving along the path.
--
-- The path consists of a series of nodes. Each node is one of the following four types:
--
-- 'PathMoveTo'
--
-- Changes the position of the path to the given pair of
-- coordinates. This is usually used as the first node of a path to
-- mark the start position. If it is used in the middle of a path then
-- the path will be disjoint and the actor will appear to jump to the
-- new position when animated.
--
-- 'PathLineTo'
--
-- Creates a straight line from the previous point to the given point.
--
-- 'PathCurveTo'
--
-- Creates a bezier curve. The end of the last node is used as the
-- first control point and the three subsequent coordinates given in
-- the node as used as the other three.
--
-- 'PathClose'
--
-- Creates a straight line from the last node to the last
-- pathMoveTo node. This can be used to close a path so that
-- it will appear as a loop when animated.
--
-- The first three types have the corresponding relative versions
-- 'PathRelMoveTo', 'PathRelLineTo' and
-- 'PathRelCurveTo'. These are exactly the same except the
-- coordinates are given relative to the previous node instead of as
-- direct screen positions.
--
-- You can build a path using the node adding functions such as
-- 'pathAddLineTo'. Alternatively the path can be described
-- in a string using a subset of the SVG path syntax. See
-- 'pathAddString' for details.
--
-- * Path is available since Clutter 1.0

-- * Class Hierarchy
-- |
-- @
-- |  'GObject'
-- |    +----'Path'
-- @

-- * Types
  Path,
  PathClass,
  PathNode,
  PathCallback,
  PathNodeType(..),

-- * Constructors
  pathNew,
  pathNewWithDescription,

-- * Methods
  pathAddMoveTo,
  pathAddRelMoveTo,
  pathAddLineTo,
  pathAddRelLineTo,
  pathAddCurveTo,
  pathAddRelCurveTo,
  pathAddClose,
  pathAddString,
  pathAddNode,
  pathAddCairoPath,
  pathGetNNodes,
  pathGetNode,
  pathGetNodes,
  pathForeach,
  pathInsertNode,
  pathRemoveNode,
  pathReplaceNode,
  pathGetDescription,
  pathSetDescription,

  pathToCairoPath,
  pathClear,
  pathGetPosition,
  pathGetLength,
-- * Attributes
  pathDescription,
  pathLength
  ) where

{# import Graphics.UI.Clutter.Types #}
{# import Graphics.UI.Clutter.Utility #}

import C2HS
import System.Glib.Attributes
import System.Glib.Properties
import Control.Monad (liftM2)
import Graphics.Rendering.Cairo.Types (Cairo)
import qualified Graphics.Rendering.Cairo.Types as Cairo

-- | Creates a new 'Path' instance with no nodes.
{# fun unsafe path_new as ^ { } -> `Path' newPath* #}

-- | Creates a new 'Path' instance with the nodes described in
--   desc. See 'pathAddString' for details of the format of
--   the string.
--
--   [@description@] A string describing the path.
--
--   [@Returns@] The newly created 'Path'.
--
-- * Since 1.0
{# fun unsafe path_new_with_description as ^ { `String' } -> `Path' newPath* #}

-- | Adds a 'PathMoveTo' type node to the path. This is usually used as
--   the first node in a path. It can also be used in the middle of
--   the path to cause the actor to jump to the new coordinate.
--
-- [@path@]  a 'Path'
--
-- [@x@]  the x coordinate
--
-- [@y@]  the y coordinate
--
-- * Since 1.0
{# fun unsafe path_add_move_to as ^ { withPath* `Path', `Int', `Int' } -> `()' #}

-- | Same as 'pathAddMoveTo' except the coordinates are relative to the previous node.
--
-- [@path@] a 'Path'
--
-- [@x@] the x coordinate
--
-- [@y@] the y coordinate
--
-- * Since 1.0
{# fun unsafe path_add_rel_move_to as ^ { withPath* `Path', `Int', `Int' } -> `()' #}

-- | Adds a PathLineTo type node to the path. This causes the actor to
--   move to the new coordinates in a straight line.
--
-- [@path@] a Path
--
-- [@x@] the x coordinate
--
-- [@y@] the y coordinate
--
-- * Since 1.0
{# fun unsafe path_add_line_to as ^ { withPath* `Path', `Int', `Int' } -> `()' #}


-- | Same as 'pathAddLineTo' except the coordinates are relative to the previous node.
--
-- [@path@] a 'Path'
--
-- [@x@] the x coordinate
--
-- [@y@] the y coordinate
--
-- * Since 1.0
{# fun unsafe path_add_rel_line_to as ^ { withPath* `Path', `Int', `Int' } -> `()' #}

-- | Adds a PathCurveTo type node to the path. This causes
--   the actor to follow a Bezier from the last node to (x_3, y_3)
--   using (x_1, y_1) and (x_2,y_2) as control points.
--
-- [@path@] a 'Path'
--
-- [@x_1@] the x coordinate of the first control point
--
-- [@y_1@] the y coordinate of the first control point
--
-- [@x_2@] the x coordinate of the second control point
--
-- [@y_2@] the y coordinate of the second control point
--
-- [@x_3@] the x coordinate of the third control point
--
-- [@y_3@] the y coordinate of the third control point
--
-- * Since 1.0
{# fun unsafe path_add_curve_to as ^ { withPath* `Path', `Int', `Int', `Int', `Int', `Int', `Int' } -> `()' #}


-- | Same as 'pathAddCurveTo' except the coordinates are
--   relative to the previous node.
--
--  [@path@]: a 'Path'
--
--  [@x_1@] the x coordinate of the first control point
--
--  [@y_1@] the y coordinate of the first control point
--
--  [@x_2@] the x coordinate of the second control point
--
--  [@y_2@] the y coordinate of the second control point
--
--  [@x_3@] the x coordinate of the third control point
--
--  [@y_3@] the y coordinate of the third control point
--
--  * Since: 1.0
{# fun unsafe path_add_rel_curve_to as ^ { withPath* `Path', `Int', `Int', `Int', `Int', `Int', `Int' } -> `()' #}


-- |  Adds a 'PathClose' type node to the path. This creates a
--  straight line from the last node to the last 'PathMoveTo'
--  type node.
--
--  [@path@] a 'Path'
--
-- * Since: 1.0
--
{# fun unsafe path_add_close as ^ { withPath* `Path' } -> `()' #}

-- | Adds new nodes to the end of the path as described by a @String@. The
--   format is a subset of the SVG path format. Each node is represented
--   by a letter and is followed by zero, one or three pairs of
--   coordinates. The coordinates can be separated by spaces or a
--   comma. The types are:
--
--  [@M@] Adds a 'PathMoveTo' node. Takes one pair of coordinates.
--
--  [@L@] Adds a 'PathLineTo' node. Takes one pair of coordinates.
--
--  [@C@] Adds a 'PathCurveTo' node. Takes three pairs of coordinates.
--
--  [@z@] Adds a 'PathClose' node. No coordinates are needed.
--
-- The M, L and C commands can also be specified in lower case which
-- means the coordinates are relative to the previous node.
--
-- For example, to move an actor in a 100 by 100 pixel square centered
-- on the point 300,300 you could use the following path:
--
--  @ M 250,350 l 0 -100 L 350,250 l 0 100 z @
--
-- If the path description isn't valid @False@ will be returned and no nodes will be added.
--
-- [@path@] a 'Path'
--
-- [@str@] a string describing the new nodes
--
-- [@Returns@] @True@ is the path description was valid or @False@ otherwise.
--
-- * Since 1.0
--
{# fun unsafe path_add_string as ^ { withPath* `Path', `String' } -> `Bool' #}



-- | Adds a node to the end of the path.
--
--  [@path@] a 'Path'
--
--  [@node@] a 'PathNode'
--
-- * Since 1.0
{# fun unsafe path_add_node as ^ { withPath* `Path', withPathNode* `PathNode' } -> `()' #}

-- | Add the nodes of the Cairo path to the end of path
--
--  [@path@] a Path
--
--  [@cairopath@] a 'CairoPath'
--
-- * Since 1.0
--
{# fun unsafe path_add_cairo_path as ^ { withPath* `Path', withCairoPath `Cairo.Path' } -> `()' #}

-- | Retrieves the number of nodes in the path.
--
-- [@path@] A 'Path'
--
-- [@Returns@] The number of nodes
--
-- * Since 1.0
--
{# fun unsafe path_get_n_nodes as ^ { withPath* `Path' } -> `Word' cIntConv #}

-- | Retrieves the node of the path indexed by index.
--
--  [@path@] a 'Path'
--
--  [@index@] the node number to retrieve
--
--  [@Returns@] The node at the location
--
-- * Since 1.0
--
{# fun unsafe path_get_node as ^ { withPath* `Path', `Int', alloca- `PathNode' peek* } -> `()' #}

-- | Returns a list of 'PathNodes'.
--
--  [@path@] a 'Path'
--
--  [@Returns@] a list of 'PathNode's in the path
--
-- * Since 1.0
--
{# fun unsafe path_get_nodes as ^ { withPath* `Path' } -> `[PathNode]' newPathNodes* #}

-- | Calls a function for each node of the path
--
-- [@path@] a 'Path'
--
-- [@callback@] the function to call with each node
--
-- * Since 1.0
--
pathForeach :: Path -> PathCallback -> IO ()
pathForeach path cpcb = withPath path $ \pathPtr -> do
                        funcPtr <- newPathCallback cpcb
                        --CHECKME: unsafe?
                        {# call unsafe path_foreach #} pathPtr funcPtr nullPtr
                        freeHaskellFunPtr funcPtr

-- | Inserts node into the path before the node at the given
--   offset. If index is negative it will append the node to the end
--   of the path.
--
-- [@path@] a 'Path'
--
-- [@index@] offset of where to insert the node
--
-- [@node@] the node to insert
--
-- * Since 1.0
--
{# fun unsafe path_insert_node as ^ { withPath* `Path', `Int', withPathNode* `PathNode' } -> `()' #}

-- | Removes the node at the given offset from the path.
--
-- [@path@] a 'Path'
--
-- [@index@] index of the node to remove
--
-- * Since 1.0
--
{# fun unsafe path_remove_node as ^ { withPath* `Path', cIntConv `Word' } -> `()' #}

-- | Replaces the node at a given offset index with node.
--
-- [@path@] a 'Path'
--
-- [@index@] index to the existing node
--
-- [@node@] the replacement node
--
-- *Since 1.0
--
{# fun unsafe path_replace_node as ^ { withPath* `Path', cIntConv `Word', withPathNode* `PathNode' } -> `()' #}


-- | Returns a string describing the path in the same format as used by 'pathAddString'
--
-- [@path@] a 'Path'
--
-- [@Returns@] a string description of the path
--
-- * Since 1.0
--
{# fun unsafe path_get_description as ^ { withPath* `Path' } -> `String' peekNFreeString* #}

-- | Replaces all of the nodes in the path with nodes described by
--  str. See 'pathAddString' for details of the format.
--  If the string is invalid then @False@ is returned and the path is unaltered.
--
-- [@path@] a 'Path'
--
-- [@str@] a string describing the path
--
-- [@Returns@] @True@ if the path was valid, @False@ otherwise
--
-- * Since 1.0
--
{# fun unsafe path_set_description as ^ { withPath* `Path', `String' } -> `Bool' #}

-- | Add the nodes of the ClutterPath to the path in the Cairo context.
--
-- [@path@] a 'Path'
--
-- [@cairo@] a Cairo context
--
-- * Since 1.0
--
{# fun unsafe path_to_cairo_path as ^ { withPath* `Path', withCairo `Cairo' } -> `()' #}

-- | Removes all nodes from the path.
--
-- [@path@] a 'Path'
--
-- * Since 1.0
--
{# fun unsafe path_clear as ^ { withPath* `Path' } -> `()' #}

--CHECKME: Do you want to get the position out? or is it just storage?
--CHECKME: Maybe not use type Knot = (Int, Int)
--CHECKME: is this what I want to return?

-- | The value in progress represents a position along the path where
--   0.0 is the beginning and 1.0 is the end of the path. An
--   interpolated position is then stored in position.
--
-- [@path@] a 'Path'
--
-- [@progress@] a position along the path as a fraction of its length
--
-- [@position@] location to store the position
--
-- [@Returns@] index of the node used to calculate the position.
--
-- * Since 1.0
--
pathGetPosition :: Path -> Double -> IO (Word, Knot)
pathGetPosition path progress = withPath path $ \pathptr ->
                                alloca $ \kptr -> do
                                   ret <- ({# call unsafe path_get_position #} pathptr (cFloatConv progress) (castPtr kptr))
                                   val <- peek kptr
                                   return (cIntConv ret, val)

-- | Retrieves an approximation of the total length of the path.
--
-- [@path@] a 'Path'
--
-- [@Returns@] the length of the path
--
-- * Since 1.0
--
{# fun unsafe path_get_length as ^ { withPath* `Path' } -> `Word' cIntConv #}


-- | SVG-style description of the path.
--
-- Default value: \"\"
--
pathDescription :: Attr Path String
pathDescription = newAttrFromStringProperty "description"

-- | An approximation of the total length of the path.
--
-- Default value: 0
--
pathLength :: ReadAttr Path Word
pathLength = readNamedAttr "length" pathGetLength