-- -*-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 {# 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 ())