clutterhs-0.1: Graphics/UI/Clutter/Timeline.chs
-- -*-haskell-*-
-- Clutter Timeline
--
-- Author : Matthew Arsenault
--
-- Created: 21 Sep 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" #}
-- | Timeline — A class for time-based events
module Graphics.UI.Clutter.Timeline (
-- * Description
-- | 'Timeline' is a base class for managing time based events such as animations.
--
-- * Class Hierarchy
-- |
-- @
-- | 'GObject'
-- | +----'Timeline'
-- @
-- * Types
Timeline,
TimelineClass,
TimelineDirection(..),
-- * Constructors
timelineNew,
timelineClone,
-- * Methods
timelineSetDuration,
timelineGetDuration,
timelineSetLoop,
timelineGetLoop,
timelineSetDelay,
timelineGetDelay,
timelineSetDirection,
timelineGetDirection,
timelineStart,
timelinePause,
timelineStop,
timelineRewind,
timelineSkip,
timelineAdvance,
timelineGetElapsedTime,
timelineGetDelta,
timelineGetProgress,
timelineIsPlaying,
timelineAddMarkerAtTime,
timelineHasMarker,
timelineListMarkers,
timelineRemoveMarker,
timelineAdvanceToMarker,
-- * Attributes
timelineDuration,
timelineLoop,
timelineDelay,
timelineDirection,
-- * Signals
onCompleted,
afterCompleted,
completed,
onMarkerReached,
afterMarkerReached,
markerReached,
onNewFrame,
afterNewFrame,
newFrame,
onPaused,
afterPaused,
paused,
onStarted,
afterStarted,
started
) where
{# import Graphics.UI.Clutter.Types #}
{# import Graphics.UI.Clutter.Signals #}
{# import Graphics.UI.Clutter.Utility #}
import C2HS
import Control.Monad (liftM)
import System.Glib.GObject
import System.Glib.Attributes
import System.Glib.Properties
import System.Glib.Signals
-- | Creates a new 'Timeline' with a duration of msecs.
--
-- [@msecs@] Duration of the timeline in milliseconds
--
-- [@Returns@] the newly created 'Timeline' instance
--
-- * Since 0.6
--
{# fun unsafe timeline_new as ^ { cIntConv `Word' } -> `Timeline' newTimeline* #}
-- | Create a new 'Timeline' instance which has property values
-- matching that of supplied timeline. The cloned timeline will not
-- be started and will not be positioned to the current position of
-- timeline: you will have to start it with 'timelineStart'.
--
-- [@timeline@] 'Timeline' to duplicate.
--
-- [@Returns@] a new 'Timeline', cloned from timeline
--
-- * Since 0.4
--
{# fun unsafe timeline_clone as ^ { withTimeline* `Timeline'} -> `Timeline' newTimeline* #}
-- | Sets the duration of the timeline, in milliseconds. The speed of
-- the timeline depends on the ClutterTimeline:fps setting.
--
-- [@timeline@] a 'Timeline'
--
-- [@msecs@] duration of the timeline in milliseconds
--
-- * Since 0.6
--
{# fun unsafe timeline_set_duration as ^ { withTimeline* `Timeline', cIntConv `Word' } -> `()' #}
-- | Retrieves the duration of a 'Timeline' in milliseconds. See
-- 'timelineSetDuration'.
--
-- [@timeline@] a 'Timeline'
--
-- [@Returns@] the duration of the timeline, in milliseconds.
--
-- * Since 0.6
--
{# fun unsafe timeline_get_duration as ^ { withTimeline* `Timeline' } -> `Word' cIntConv #}
-- | Sets whether timeline should loop.
--
-- [@timeline@] a 'Timeline'
--
-- [@loop@] @True@ for enable looping
--
{# fun unsafe timeline_set_loop as ^ { withTimeline* `Timeline', `Bool' } -> `()' #}
-- | Gets whether timeline is looping
--
-- [@timeline@] a 'Timeline'
--
-- [@Returns@] @True@ if the timeline is looping
--
{# fun unsafe timeline_get_loop as ^ { withTimeline* `Timeline' } -> `Bool' #}
-- | Sets the delay, in milliseconds, before timeline should start.
--
-- [@timeline@] a 'Timeline'
--
-- [@msecs@] delay in milliseconds
--
-- * Since 0.4
--
{# fun unsafe timeline_set_delay as ^ { withTimeline* `Timeline', cIntConv `Word' } -> `()' #}
-- | Retrieves the delay set using 'timelineSetDelay'.
--
-- [@timeline@] a 'Timeline'
--
-- [@Returns@] the delay in milliseconds.
--
-- * Since 0.4
--
{# fun unsafe timeline_get_delay as ^ { withTimeline* `Timeline' } -> `Word' cIntConv #}
-- | Sets the direction of timeline, either TimelineForward or
-- TimelineBackward.
--
-- [@timeline@] a 'Timeline'
--
-- [@direction@] the direction of the timeline
--
-- * Since 0.6
--
{# fun unsafe timeline_set_direction as ^
{ withTimeline* `Timeline', cFromEnum `TimelineDirection' } -> `()' #}
-- | Retrieves the direction of the timeline set with
-- 'TimelineSetDirection'.
--
-- [@timeline@] a 'Timeline'
--
-- [@Returns@] the direction of the timeline
--
-- * Since 0.6
--
{# fun unsafe timeline_get_direction as ^
{ withTimeline* `Timeline' } -> `TimelineDirection' cToEnum #}
-- | Starts the 'Timeline' playing.
{# fun timeline_start as ^ { withTimeline* `Timeline' } -> `()' #}
-- | Pauses the 'Timeline' on current frame
{# fun timeline_pause as ^ { withTimeline* `Timeline' } -> `()' #}
-- | Stops the 'Timeline' and moves to frame 0
{# fun timeline_stop as ^ { withTimeline* `Timeline' } -> `()' #}
-- | Rewinds ClutterTimeline to the first frame if its direction is
-- TimelineForward and the last frame if it is TimelineBackward.
{# fun timeline_rewind as ^ { withTimeline* `Timeline' } -> `()' #}
-- | Advance timeline by the requested time in milliseconds
--
-- [@timeline@] A 'Timeline'
--
-- [@msecs@] Amount of time to skip
--
{# fun timeline_skip as ^ { withTimeline* `Timeline', cIntConv `Word' } -> `()' #}
--CHECKME: Since it's skipping the given time, but does it skip others? mark unsafe or not?
-- | Advance timeline to the requested point. The point is given as a
-- time in milliseconds since the timeline started.
--
-- * Note
--
-- The timeline will not emit the "new-frame" signal for the given
-- time. The first ::new-frame signal after the call to
-- 'timelineAdvance' will be emit the skipped markers.
--
-- [@timeline@] A 'Timeline'
--
-- [@msecs@] Time to advance to
--
{# fun unsafe timeline_advance as ^ { withTimeline* `Timeline', cIntConv `Word' } -> `()' #}
-- | Request the current time position of the timeline.
--
-- [@timeline@] A 'Timeline'
--
-- [@Returns@] current elapsed time in milliseconds.
--
{# fun unsafe timeline_get_elapsed_time as ^ { withTimeline* `Timeline' } -> `Word' cIntConv #}
--TODO: Links to all the signals in the doc
-- | Retrieves the amount of time elapsed since the last 'Timeline'::new-frame signal.
--
-- This function is only useful inside handlers for the ::new-frame
-- signal, and its behaviour is undefined if the timeline is not
-- playing.
--
-- [@timeline@] a 'Timeline'
--
-- [@Returns@] the amount of time in milliseconds elapsed since the last frame
--
-- * Since 0.6
--
{# fun unsafe timeline_get_delta as ^ { withTimeline* `Timeline' } -> `Word' cIntConv #}
-- | The position of the timeline in a [0, 1] interval.
--
-- [@timeline@] a 'Timeline'
--
-- [@Returns@] the position of the timeline.
--
-- * Since 0.6
--
{# fun unsafe timeline_get_progress as ^ { withTimeline* `Timeline' } -> `Double' #}
-- | Queries state of a 'Timeline'.
--
-- [@timeline@] A 'Timeline'
--
-- [@Returns@] @True@ if timeline is currently playing
--
{# fun unsafe timeline_is_playing as ^ { withTimeline* `Timeline' } -> `Bool' #}
-- | Adds a named marker that will be hit when the timeline has been
-- running for msecs milliseconds. Markers are unique string
-- identifiers for a given time. Once timeline reaches msecs, it
-- will emit a ::marker-reached signal for each marker attached to
-- that time.
--
-- A marker can be removed with 'timelineRemoveMarker'. The timeline
-- can be advanced to a marker using 'timelineAdvanceToMarker'.
--
-- [@timeline@] a 'Timeline'
--
-- [@marker_name@] the unique name for this marker
--
-- [@msecs@] position of the marker in milliseconds
--
-- * Since 0.8
--
{# fun unsafe timeline_add_marker_at_time as ^
{ withTimeline* `Timeline', `String', cIntConv `Word' } -> `()' #}
-- | Checks whether timeline has a marker set with the given name.
--
-- [@timeline@] a 'Timeline'
--
-- [@marker_name@] the name of the marker
--
-- [@Returns@] @True@ if the marker was found
--
-- * Since 0.8
--
{# fun unsafe timeline_has_marker as ^ { withTimeline* `Timeline', `String' } -> `Bool' #}
--CHECKME: Does the returned gchar** need to be freed from this?
--CHECME: Unicode?
--TODO: Maybe better way to get char** out
-- | Retrieves the list of markers at time msecs. If frame_num is a
-- negative integer, all the markers attached to timeline will be
-- returned.
--
-- [@timeline@] a 'Timeline'
--
-- [@msecs@] the time to check, or -1
--
-- [@Returns@] A list of markers returned
--
-- * Since 0.8
--
timelineListMarkers :: Timeline -> Int -> IO [String]
timelineListMarkers tml time = withTimeline tml $ \tmlptr ->
alloca $ \intptr -> do
strArrayPtr <- {# call unsafe timeline_list_markers #} tmlptr (cIntConv time) intptr
num <- peek intptr
strPtrList <- peekArray (cIntConv num) strArrayPtr
mapM peekNFreeString strPtrList
-- | Removes marker_name, if found, from timeline.
--
-- [@timeline@] a 'Timeline'
--
-- [@marker_name@] the name of the marker to remove
--
-- * Since 0.8
--
{# fun unsafe timeline_remove_marker as ^ { withTimeline* `Timeline', `String' } -> `()' #}
-- | Advances timeline to the time of the given marker_name.
--
-- * Note
--
-- Like 'timelineAdvance', this function will not emit the "new-frame"
-- for the time where marker_name is set, nor it will emit
-- "marker-reached" for marker_name.
--
-- [@timeline@] a 'Timeline'
--
-- [@marker_name@] the name of the marker
--
-- * Since 0.8
--
{# fun unsafe timeline_advance_to_marker as ^ { withTimeline* `Timeline', `String' } -> `()' #}
-- | Duration of the timeline in milliseconds, depending on the
-- 'Timeline':fps value.
--
-- Default value: 1000
--
-- * Since 0.6
--
timelineDuration :: Attr Timeline Word
timelineDuration = newNamedAttr "duration" timelineGetDuration timelineSetDuration
-- | Whether the timeline should automatically rewind and restart.
--
-- Default value: @False@
--
timelineLoop :: Attr Timeline Bool
timelineLoop = newNamedAttr "loop" timelineGetLoop timelineSetLoop
-- | A delay, in milliseconds, that should be observed by the timeline
-- before actually starting.
--
-- Default value: 0
--
-- * Since 0.4
--
timelineDelay :: Attr Timeline Word
timelineDelay = newNamedAttr "delay" timelineGetDelay timelineSetDelay
-- | The direction of the timeline, either TimelineForward
-- or TimelineBackward.
--
-- Default value: TimelineForward
--
-- * Since 0.6
--
timelineDirection :: Attr Timeline TimelineDirection
timelineDirection = newNamedAttr "direction" timelineGetDirection timelineSetDirection
--TODO: Check these
--onCompleted, afterCompleted :: Timeline -> IO () -> IO (ConnectId Timeline)
-- | The ::completed signal is emitted when the timeline reaches the
-- number of frames specified by the 'Timeline':num-frames
-- property.
--completed :: Signal Timeline (IO ())
onMarkerReached, afterMarkerReached :: Timeline -> (String -> Word -> IO ()) -> IO (ConnectId Timeline)
onMarkerReached = connect_STRING_WORD__NONE "marker-reached" False
afterMarkerReached = connect_STRING_WORD__NONE "marker-reached" True
--TODO: Code part of this doc
-- | The ::marker-reached signal is emitted each time a timeline
-- reaches a marker set with 'timelineAddMarkerAtTime'. This signal
-- is detailed with the name of the marker as well, so it is
-- possible to connect a callback to the ::marker-reached signal for
-- a specific marker with:
--
-- TODO: The example
--
-- In the example, the first callback will be invoked for both the
-- \"foo\" and \"bar\" marker, while the second and third callbacks
-- will be invoked for the \"foo\" or \"bar\" markers, respectively.
--
-- [@timeline@] the 'Timeline' which received the signal
--
-- [@marker_name@] the name of the marker reached
--
-- [@msecs@] the elapsed time
--
-- * Since 0.8
--
markerReached :: Signal Timeline (String -> Word -> IO ())
markerReached = Signal (connect_STRING_WORD__NONE "marker-reached")
onNewFrame, afterNewFrame :: Timeline -> (Int -> IO ()) -> IO (ConnectId Timeline)
onNewFrame = connect_INT__NONE "new-frame" False
afterNewFrame = connect_INT__NONE "new-frame" True
-- | The ::new-frame signal is emitted for each timeline running
-- timeline before a new frame is drawn to give animations a chance
-- to update the scene.
--
-- [@timeline@] the timeline which received the signal
--
-- [@msecs@] the elapsed time between 0 and duration
--
newFrame :: Signal Timeline (Int -> IO ())
newFrame = Signal (connect_INT__NONE "new-frame")
instance Playable Timeline where
started = Signal (connect_NONE__NONE "started")
onStarted = connect_NONE__NONE "started" False
afterStarted = connect_NONE__NONE "started" True
completed = Signal (connect_NONE__NONE "completed")
onCompleted = connect_NONE__NONE "completed" False
afterCompleted = connect_NONE__NONE "completed" True
paused = Signal (connect_NONE__NONE "paused")
onPaused = connect_NONE__NONE "paused" False
afterPaused = connect_NONE__NONE "paused" True
-- | The ::paused signal is emitted when 'timelinePause' is invoked.
-- paused :: Signal Timeline (IO ())
-- onStarted, afterStarted :: Timeline -> IO () -> IO (ConnectId Timeline)
-- | The ::started signal is emitted when the timeline starts its
-- run. This might be as soon as 'timelineStart' is invoked or after
-- the delay set in the 'Timeline':delay property has expired.
--started :: Signal Timeline (IO ())