Pick the right function to load a Pixbuf on Windows.

{-# LANGUAGE CPP #-}
-- -*-haskell-*-
--  GIMP Toolkit (GTK) Pixbuf Animation
--
--  Author : Matthew Arsenault
--
--  Created: 14 November 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 2.1 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.
--
-- |
-- Maintainer  : gtk2hs-users@lists.sourceforge.net
-- Stability   : provisional
-- Portability : portable (depends on GHC)
--
module Graphics.UI.Gtk.Gdk.PixbufAnimation (
-- * Class Hierarchy
-- |
-- @
-- |  'GObject'
-- |   +----'PixbufAnimation'
-- |        +----'PixbufSimpleAnim'
-- @

-- * Types
  PixbufAnimation,
  PixbufAnimationClass,
  castToPixbufAnimation, gTypePixbufAnimation,
  toPixbufAnimation,

  PixbufAnimationIter,
  PixbufAnimationIterClass,
  castToPixbufAnimationIter, gTypePixbufAnimationIter,
  toPixbufAnimationIter,

  PixbufSimpleAnim,
  PixbufSimpleAnimClass,
  castToPixbufSimpleAnim, gTypePixbufSimpleAnim,
  toPixbufSimpleAnim,

-- * Constructors
  pixbufAnimationNewFromFile,
#if GTK_CHECK_VERSION(2,8,0)
  pixbufSimpleAnimNew,
#endif

-- * Methods
  pixbufAnimationGetWidth,
  pixbufAnimationGetHeight,
  pixbufAnimationGetIter,
  pixbufAnimationIsStaticImage,
  pixbufAnimationGetStaticImage,
  pixbufAnimationIterAdvance,
  pixbufAnimationIterGetDelayTime,
  pixbufAnimationIterOnCurrentlyLoadingFrame,
  pixbufAnimationIterGetPixbuf,
#if GTK_CHECK_VERSION(2,8,0)
  pixbufSimpleAnimAddFrame,
#endif

#if GTK_CHECK_VERSION(2,18,0)
  pixbufSimpleAnimSetLoop,
  pixbufSimpleAnimGetLoop
#endif
  ) where

import Control.Monad (liftM)
import System.Glib.FFI
import System.Glib.UTFString
import System.Glib.GDateTime
import System.Glib.GObject
{#import Graphics.UI.Gtk.Types#}
import System.Glib.GError	(GError(..), GErrorClass(..), GErrorDomain,
				propagateGError)
{# import Graphics.UI.Gtk.Gdk.Pixbuf #}

{# context prefix="gdk" #}

--CHECKME: Domain error doc, GFileError ???
-- | Creates a new animation by loading it from a file. The file
--   format is detected automatically. If the file's format does not
--   support multi-frame images, then an animation with a single frame
--   will be created. Possible errors are in the 'PixbufError' and
--   'GFileError' domains.
--
-- Any of several error conditions may occur: the file could not be
-- opened, there was no loader for the file's format, there was not
-- enough memory to allocate the image buffer, or the image file
-- contained invalid data.
--
-- * If an error occurs, the function will throw an exception that can
--   be caught using e.g. 'System.Glib.GError.catchGErrorJust' and one of the
--   error codes in 'PixbufError' or 'GFileError'
--
pixbufAnimationNewFromFile :: FilePath               -- ^ Name of file to load, in the GLib file name encoding
                           -> IO PixbufAnimation     -- ^ A newly-created animation
pixbufAnimationNewFromFile fname =
  constructNewGObject mkPixbufAnimation $
  propagateGError $ \errPtrPtr ->
     withUTFString fname $ \strPtr ->
#if defined (WIN32) && GTK_CHECK_VERSION(2,6,5)
     {#call unsafe pixbuf_animation_new_from_file_utf8#} strPtr errPtrPtr
#else
     {#call unsafe pixbuf_animation_new_from_file#} strPtr errPtrPtr
#endif

-- | Queries the width of the bounding box of a pixbuf animation.
pixbufAnimationGetWidth :: PixbufAnimation -- ^ An animation.
                        -> IO Int          -- ^ Width of the bounding box of the animation.
pixbufAnimationGetWidth self = liftM fromIntegral $ {#call unsafe pixbuf_animation_get_width#} self

-- | Queries the height of the bounding box of a pixbuf animation.
pixbufAnimationGetHeight :: PixbufAnimation  -- ^ An animation.
                         -> IO Int           -- ^ Height of the bounding box of the animation.
pixbufAnimationGetHeight self = liftM fromIntegral $ {#call unsafe pixbuf_animation_get_height#} self

-- | Get an iterator for displaying an animation. The iterator
--   provides the frames that should be displayed at a given time. The
--   start time would normally come from 'gGetCurrentTime', and marks
--   the beginning of animation playback. After creating an iterator,
--   you should immediately display the pixbuf returned by
--   'pixbufAnimationIterGetPixbuf'. Then, you should install a
--   timeout (with 'timeoutAdd') or by some other mechanism ensure
--   that you'll update the image after
--   'pixbufAnimationIterGetDelayTime' milliseconds. Each time the
--   image is updated, you should reinstall the timeout with the new,
--   possibly-changed delay time.
--
-- As a shortcut, if start_time is @Nothing@, the result of
-- 'gGetCurrentTime' will be used automatically.
--
-- To update the image (i.e. possibly change the result of
-- 'pixbufAnimationIterGetPixbuf' to a new frame of the animation),
-- call 'pixbufAnimationIterAdvance'.
--
--  If you're using 'PixbufLoader', in addition to updating the image
--  after the delay time, you should also update it whenever you
--  receive the area_updated signal and
--  'pixbufAnimationIterOnCurrentlyLoadingFrame' returns @True@. In
--  this case, the frame currently being fed into the loader has
--  received new data, so needs to be refreshed. The delay time for a
--  frame may also be modified after an area_updated signal, for
--  example if the delay time for a frame is encoded in the data after
--  the frame itself. So your timeout should be reinstalled after any
--  area_updated signal.
--
-- A delay time of -1 is possible, indicating "infinite."
--
pixbufAnimationGetIter :: PixbufAnimation            -- ^ a 'PixbufAnimation'
                       -> Maybe GTimeVal             -- ^ time when the animation starts playing
                       -> IO PixbufAnimationIter     -- ^ an iterator to move over the animation
pixbufAnimationGetIter self tv = maybeWith with tv $ \stPtr ->
                                 constructNewGObject mkPixbufAnimationIter $
                                   {#call unsafe pixbuf_animation_get_iter#} self (castPtr stPtr)

-- | If you load a file with 'pixbufAnimationNewFromFile' and it turns
--   out to be a plain, unanimated image, then this function will
--   return @True@. Use 'pixbufAnimationGetStaticImage' to retrieve
--   the image.
--
pixbufAnimationIsStaticImage :: PixbufAnimation
                             -> IO Bool          -- ^ TRUE if the "animation" was really just an image
pixbufAnimationIsStaticImage self = liftM toBool $ {#call unsafe pixbuf_animation_is_static_image#} self

-- | If an animation is really just a plain image (has only one
--   frame), this function returns that image. If the animation is an
--   animation, this function returns a reasonable thing to display as
--   a static unanimated image, which might be the first frame, or
--   something more sophisticated. If an animation hasn't loaded any
--   frames yet, this function will return @Nothing@.
--
pixbufAnimationGetStaticImage :: PixbufAnimation
                              -> IO (Maybe Pixbuf) -- ^ unanimated image representing the animation
pixbufAnimationGetStaticImage self =
  maybeNull (constructNewGObject mkPixbuf) $ {#call unsafe pixbuf_animation_get_static_image#} self

-- | Possibly advances an animation to a new frame. Chooses the frame
--   based on the start time passed to 'pixbufAnimationGetIter'.
--
-- current_time would normally come from 'gGetCurrentTime', and must
-- be greater than or equal to the time passed to
-- 'pixbufAnimationGetIter', and must increase or remain unchanged
-- each time 'pixbufAnimationIterGetPixbuf' is called. That is, you
-- can't go backward in time; animations only play forward.
--
--  As a shortcut, pass @Nothing@ for the current time and
-- 'gGetCurrentTime' will be invoked on your behalf. So you only need
-- to explicitly pass current_time if you're doing something odd like
-- playing the animation at double speed.
--
-- If this function returns @False@, there's no need to update the
-- animation display, assuming the display had been rendered prior to
-- advancing; if @True@, you need to call 'animationIterGetPixbuf' and
-- update the display with the new pixbuf.
--
pixbufAnimationIterAdvance :: PixbufAnimationIter  -- ^ A 'PixbufAnimationIter'
                           -> Maybe GTimeVal       -- ^ current time
                           -> IO Bool              -- ^ @True@ if the image may need updating
pixbufAnimationIterAdvance iter currentTime = liftM toBool $ maybeWith with currentTime $ \tvPtr ->
                                                {# call unsafe pixbuf_animation_iter_advance #} iter (castPtr tvPtr)

-- | Gets the number of milliseconds the current pixbuf should be
--   displayed, or -1 if the current pixbuf should be displayed
--   forever. 'timeoutAdd' conveniently takes a timeout in
--   milliseconds, so you can use a timeout to schedule the next
--   update.
--
pixbufAnimationIterGetDelayTime :: PixbufAnimationIter  -- ^ an animation iterator
                                -> IO Int               -- ^ delay time in milliseconds (thousandths of a second)
pixbufAnimationIterGetDelayTime self = liftM fromIntegral $
  {#call unsafe pixbuf_animation_iter_get_delay_time#} self

-- | Used to determine how to respond to the area_updated signal on
--   'PixbufLoader' when loading an animation. area_updated is emitted
--   for an area of the frame currently streaming in to the loader. So
--   if you're on the currently loading frame, you need to redraw the
--   screen for the updated area.
--
pixbufAnimationIterOnCurrentlyLoadingFrame :: PixbufAnimationIter
                                           -> IO Bool              -- ^ @True@ if the frame we're on is partially loaded, or the last frame
pixbufAnimationIterOnCurrentlyLoadingFrame iter = liftM toBool $
  {# call unsafe pixbuf_animation_iter_on_currently_loading_frame #} iter

--CHECKME: referencing, usage of constructNewGObject
-- | Gets the current pixbuf which should be displayed; the pixbuf will
-- be the same size as the animation itself
-- ('pixbufAnimationGetWidth', 'pixbufAnimationGetHeight'). This
-- pixbuf should be displayed for 'pixbufAnimationIterGetDelayTime'
-- milliseconds. The caller of this function does not own a reference
-- to the returned pixbuf; the returned pixbuf will become invalid
-- when the iterator advances to the next frame, which may happen
-- anytime you call 'pixbufAnimationIterAdvance'. Copy the pixbuf to
-- keep it (don't just add a reference), as it may get recycled as you
-- advance the iterator.
--
pixbufAnimationIterGetPixbuf :: PixbufAnimationIter -- ^ an animation iterator
                                -> IO Pixbuf        -- ^ the pixbuf to be displayed
pixbufAnimationIterGetPixbuf iter = constructNewGObject mkPixbuf $
   {# call unsafe pixbuf_animation_iter_get_pixbuf #} iter

#if GTK_CHECK_VERSION(2,8,0)
-- | Creates a new, empty animation.
--
-- * Available since Gtk+ version 2.8
--
pixbufSimpleAnimNew :: Int   -- ^ the width of the animation
                    -> Int   -- ^ the height of the animation
                    -> Float -- ^ the speed of the animation, in frames per second
                    -> IO PixbufSimpleAnim  -- ^ a newly allocated 'PixbufSimpleAnim'
pixbufSimpleAnimNew width height rate = constructNewGObject mkPixbufSimpleAnim $
  {#call unsafe pixbuf_simple_anim_new#} (fromIntegral width) (fromIntegral height) (realToFrac rate)

-- | Adds a new frame to animation. The pixbuf must have the
--   dimensions specified when the animation was constructed.
--
-- * Available since Gtk+ version 2.8
--
pixbufSimpleAnimAddFrame :: PixbufSimpleAnim   -- ^ a 'PixbufSimpleAnim'
                         -> Pixbuf             -- ^ the pixbuf to add
                         -> IO ()
pixbufSimpleAnimAddFrame psa pb = {#call unsafe pixbuf_simple_anim_add_frame#} psa pb

#endif

#if GTK_CHECK_VERSION(2,18,0)

-- | Sets whether animation should loop indefinitely when it reaches
--   the end.
--
-- * Available since Gtk+ version 2.18
--
pixbufSimpleAnimSetLoop :: PixbufSimpleAnim  -- ^ a 'PixbufSimpleAnim'
                           -> Bool           -- ^ whether to loop the animation
                           -> IO ()
pixbufSimpleAnimSetLoop animation loop = {#call unsafe pixbuf_simple_anim_set_loop#} animation (fromBool loop)

-- | Gets whether animation should loop indefinitely when it reaches
--   the end.
--
-- * Available since Gtk+ version 2.18
--
pixbufSimpleAnimGetLoop :: PixbufSimpleAnim  -- ^ a 'PixbufSimpleAnim'
                           -> IO Bool        -- ^ @True@ if the animation loops forever, @False@ otherwise
pixbufSimpleAnimGetLoop animation = liftM toBool $ {#call unsafe pixbuf_simple_anim_get_loop#} animation

#endif

{-# LANGUAGE CPP #-}
-- -*-haskell-*-
--  GIMP Toolkit (GTK) Pixbuf Animation
--
--  Author : Matthew Arsenault
--
--  Created: 14 November 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 2.1 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.
--
-- |
-- Maintainer  : gtk2hs-users@lists.sourceforge.net
-- Stability   : provisional
-- Portability : portable (depends on GHC)
--
module Graphics.UI.Gtk.Gdk.PixbufAnimation (
-- * Class Hierarchy
-- |
-- @
-- |  'GObject'
-- |   +----'PixbufAnimation'
-- |        +----'PixbufSimpleAnim'
-- @

-- * Types
  PixbufAnimation,
  PixbufAnimationClass,
  castToPixbufAnimation, gTypePixbufAnimation,
  toPixbufAnimation,

  PixbufAnimationIter,
  PixbufAnimationIterClass,
  castToPixbufAnimationIter, gTypePixbufAnimationIter,
  toPixbufAnimationIter,

  PixbufSimpleAnim,
  PixbufSimpleAnimClass,
  castToPixbufSimpleAnim, gTypePixbufSimpleAnim,
  toPixbufSimpleAnim,

-- * Constructors
  pixbufAnimationNewFromFile,
#if GTK_CHECK_VERSION(2,8,0)
  pixbufSimpleAnimNew,
#endif

-- * Methods
  pixbufAnimationGetWidth,
  pixbufAnimationGetHeight,
  pixbufAnimationGetIter,
  pixbufAnimationIsStaticImage,
  pixbufAnimationGetStaticImage,
  pixbufAnimationIterAdvance,
  pixbufAnimationIterGetDelayTime,
  pixbufAnimationIterOnCurrentlyLoadingFrame,
  pixbufAnimationIterGetPixbuf,
#if GTK_CHECK_VERSION(2,8,0)
  pixbufSimpleAnimAddFrame,
#endif

#if GTK_CHECK_VERSION(2,18,0)
  pixbufSimpleAnimSetLoop,
  pixbufSimpleAnimGetLoop
#endif
  ) where

import Control.Monad (liftM)
import System.Glib.FFI
import System.Glib.UTFString
import System.Glib.GDateTime
import System.Glib.GObject
{#import Graphics.UI.Gtk.Types#}
import System.Glib.GError	(GError(..), GErrorClass(..), GErrorDomain,
				propagateGError)
{# import Graphics.UI.Gtk.Gdk.Pixbuf #}

{# context prefix="gdk" #}

--CHECKME: Domain error doc, GFileError ???
-- | Creates a new animation by loading it from a file. The file
--   format is detected automatically. If the file's format does not
--   support multi-frame images, then an animation with a single frame
--   will be created. Possible errors are in the 'PixbufError' and
--   'GFileError' domains.
--
-- Any of several error conditions may occur: the file could not be
-- opened, there was no loader for the file's format, there was not
-- enough memory to allocate the image buffer, or the image file
-- contained invalid data.
--
-- * If an error occurs, the function will throw an exception that can
--   be caught using e.g. 'System.Glib.GError.catchGErrorJust' and one of the
--   error codes in 'PixbufError' or 'GFileError'
--
pixbufAnimationNewFromFile :: FilePath               -- ^ Name of file to load, in the GLib file name encoding
                           -> IO PixbufAnimation     -- ^ A newly-created animation
pixbufAnimationNewFromFile fname =
  constructNewGObject mkPixbufAnimation $
  propagateGError $ \errPtrPtr ->
     withUTFString fname $ \strPtr ->
     {#call unsafe pixbuf_animation_new_from_file#} strPtr errPtrPtr

-- | Queries the width of the bounding box of a pixbuf animation.
pixbufAnimationGetWidth :: PixbufAnimation -- ^ An animation.
                        -> IO Int          -- ^ Width of the bounding box of the animation.
pixbufAnimationGetWidth self = liftM fromIntegral $ {#call unsafe pixbuf_animation_get_width#} self

-- | Queries the height of the bounding box of a pixbuf animation.
pixbufAnimationGetHeight :: PixbufAnimation  -- ^ An animation.
                         -> IO Int           -- ^ Height of the bounding box of the animation.
pixbufAnimationGetHeight self = liftM fromIntegral $ {#call unsafe pixbuf_animation_get_height#} self

-- | Get an iterator for displaying an animation. The iterator
--   provides the frames that should be displayed at a given time. The
--   start time would normally come from 'gGetCurrentTime', and marks
--   the beginning of animation playback. After creating an iterator,
--   you should immediately display the pixbuf returned by
--   'pixbufAnimationIterGetPixbuf'. Then, you should install a
--   timeout (with 'timeoutAdd') or by some other mechanism ensure
--   that you'll update the image after
--   'pixbufAnimationIterGetDelayTime' milliseconds. Each time the
--   image is updated, you should reinstall the timeout with the new,
--   possibly-changed delay time.
--
-- As a shortcut, if start_time is @Nothing@, the result of
-- 'gGetCurrentTime' will be used automatically.
--
-- To update the image (i.e. possibly change the result of
-- 'pixbufAnimationIterGetPixbuf' to a new frame of the animation),
-- call 'pixbufAnimationIterAdvance'.
--
--  If you're using 'PixbufLoader', in addition to updating the image
--  after the delay time, you should also update it whenever you
--  receive the area_updated signal and
--  'pixbufAnimationIterOnCurrentlyLoadingFrame' returns @True@. In
--  this case, the frame currently being fed into the loader has
--  received new data, so needs to be refreshed. The delay time for a
--  frame may also be modified after an area_updated signal, for
--  example if the delay time for a frame is encoded in the data after
--  the frame itself. So your timeout should be reinstalled after any
--  area_updated signal.
--
-- A delay time of -1 is possible, indicating "infinite."
--
pixbufAnimationGetIter :: PixbufAnimation            -- ^ a 'PixbufAnimation'
                       -> Maybe GTimeVal             -- ^ time when the animation starts playing
                       -> IO PixbufAnimationIter     -- ^ an iterator to move over the animation
pixbufAnimationGetIter self tv = maybeWith with tv $ \stPtr ->
                                 constructNewGObject mkPixbufAnimationIter $
                                   {#call unsafe pixbuf_animation_get_iter#} self (castPtr stPtr)

-- | If you load a file with 'pixbufAnimationNewFromFile' and it turns
--   out to be a plain, unanimated image, then this function will
--   return @True@. Use 'pixbufAnimationGetStaticImage' to retrieve
--   the image.
--
pixbufAnimationIsStaticImage :: PixbufAnimation
                             -> IO Bool          -- ^ TRUE if the "animation" was really just an image
pixbufAnimationIsStaticImage self = liftM toBool $ {#call unsafe pixbuf_animation_is_static_image#} self

-- | If an animation is really just a plain image (has only one
--   frame), this function returns that image. If the animation is an
--   animation, this function returns a reasonable thing to display as
--   a static unanimated image, which might be the first frame, or
--   something more sophisticated. If an animation hasn't loaded any
--   frames yet, this function will return @Nothing@.
--
pixbufAnimationGetStaticImage :: PixbufAnimation
                              -> IO (Maybe Pixbuf) -- ^ unanimated image representing the animation
pixbufAnimationGetStaticImage self =
  maybeNull (constructNewGObject mkPixbuf) $ {#call unsafe pixbuf_animation_get_static_image#} self

-- | Possibly advances an animation to a new frame. Chooses the frame
--   based on the start time passed to 'pixbufAnimationGetIter'.
--
-- current_time would normally come from 'gGetCurrentTime', and must
-- be greater than or equal to the time passed to
-- 'pixbufAnimationGetIter', and must increase or remain unchanged
-- each time 'pixbufAnimationIterGetPixbuf' is called. That is, you
-- can't go backward in time; animations only play forward.
--
--  As a shortcut, pass @Nothing@ for the current time and
-- 'gGetCurrentTime' will be invoked on your behalf. So you only need
-- to explicitly pass current_time if you're doing something odd like
-- playing the animation at double speed.
--
-- If this function returns @False@, there's no need to update the
-- animation display, assuming the display had been rendered prior to
-- advancing; if @True@, you need to call 'animationIterGetPixbuf' and
-- update the display with the new pixbuf.
--
pixbufAnimationIterAdvance :: PixbufAnimationIter  -- ^ A 'PixbufAnimationIter'
                           -> Maybe GTimeVal       -- ^ current time
                           -> IO Bool              -- ^ @True@ if the image may need updating
pixbufAnimationIterAdvance iter currentTime = liftM toBool $ maybeWith with currentTime $ \tvPtr ->
                                                {# call unsafe pixbuf_animation_iter_advance #} iter (castPtr tvPtr)

-- | Gets the number of milliseconds the current pixbuf should be
--   displayed, or -1 if the current pixbuf should be displayed
--   forever. 'timeoutAdd' conveniently takes a timeout in
--   milliseconds, so you can use a timeout to schedule the next
--   update.
--
pixbufAnimationIterGetDelayTime :: PixbufAnimationIter  -- ^ an animation iterator
                                -> IO Int               -- ^ delay time in milliseconds (thousandths of a second)
pixbufAnimationIterGetDelayTime self = liftM fromIntegral $
  {#call unsafe pixbuf_animation_iter_get_delay_time#} self

-- | Used to determine how to respond to the area_updated signal on
--   'PixbufLoader' when loading an animation. area_updated is emitted
--   for an area of the frame currently streaming in to the loader. So
--   if you're on the currently loading frame, you need to redraw the
--   screen for the updated area.
--
pixbufAnimationIterOnCurrentlyLoadingFrame :: PixbufAnimationIter
                                           -> IO Bool              -- ^ @True@ if the frame we're on is partially loaded, or the last frame
pixbufAnimationIterOnCurrentlyLoadingFrame iter = liftM toBool $
  {# call unsafe pixbuf_animation_iter_on_currently_loading_frame #} iter

--CHECKME: referencing, usage of constructNewGObject
-- | Gets the current pixbuf which should be displayed; the pixbuf will
-- be the same size as the animation itself
-- ('pixbufAnimationGetWidth', 'pixbufAnimationGetHeight'). This
-- pixbuf should be displayed for 'pixbufAnimationIterGetDelayTime'
-- milliseconds. The caller of this function does not own a reference
-- to the returned pixbuf; the returned pixbuf will become invalid
-- when the iterator advances to the next frame, which may happen
-- anytime you call 'pixbufAnimationIterAdvance'. Copy the pixbuf to
-- keep it (don't just add a reference), as it may get recycled as you
-- advance the iterator.
--
pixbufAnimationIterGetPixbuf :: PixbufAnimationIter -- ^ an animation iterator
                                -> IO Pixbuf        -- ^ the pixbuf to be displayed
pixbufAnimationIterGetPixbuf iter = constructNewGObject mkPixbuf $
   {# call unsafe pixbuf_animation_iter_get_pixbuf #} iter

#if GTK_CHECK_VERSION(2,8,0)
-- | Creates a new, empty animation.
--
-- * Available since Gtk+ version 2.8
--
pixbufSimpleAnimNew :: Int   -- ^ the width of the animation
                    -> Int   -- ^ the height of the animation
                    -> Float -- ^ the speed of the animation, in frames per second
                    -> IO PixbufSimpleAnim  -- ^ a newly allocated 'PixbufSimpleAnim'
pixbufSimpleAnimNew width height rate = constructNewGObject mkPixbufSimpleAnim $
  {#call unsafe pixbuf_simple_anim_new#} (fromIntegral width) (fromIntegral height) (realToFrac rate)

-- | Adds a new frame to animation. The pixbuf must have the
--   dimensions specified when the animation was constructed.
--
-- * Available since Gtk+ version 2.8
--
pixbufSimpleAnimAddFrame :: PixbufSimpleAnim   -- ^ a 'PixbufSimpleAnim'
                         -> Pixbuf             -- ^ the pixbuf to add
                         -> IO ()
pixbufSimpleAnimAddFrame psa pb = {#call unsafe pixbuf_simple_anim_add_frame#} psa pb

#endif

#if GTK_CHECK_VERSION(2,18,0)

-- | Sets whether animation should loop indefinitely when it reaches
--   the end.
--
-- * Available since Gtk+ version 2.18
--
pixbufSimpleAnimSetLoop :: PixbufSimpleAnim  -- ^ a 'PixbufSimpleAnim'
                           -> Bool           -- ^ whether to loop the animation
                           -> IO ()
pixbufSimpleAnimSetLoop animation loop = {#call unsafe pixbuf_simple_anim_set_loop#} animation (fromBool loop)

-- | Gets whether animation should loop indefinitely when it reaches
--   the end.
--
-- * Available since Gtk+ version 2.18
--
pixbufSimpleAnimGetLoop :: PixbufSimpleAnim  -- ^ a 'PixbufSimpleAnim'
                           -> IO Bool        -- ^ @True@ if the animation loops forever, @False@ otherwise
pixbufSimpleAnimGetLoop animation = liftM toBool $ {#call unsafe pixbuf_simple_anim_get_loop#} animation

#endif


Add desciption docs in SourceBuffer.chs

Add desciption docs in SourceBuffer.chs

{-# LANGUAGE CPP #-}
-- -*-haskell-*-
--  GIMP Toolkit (GTK) SourceBuffer
--
--  Author : Peter Gavin, Andy Stewart
--  derived from sourceview bindings by Axel Simon and Duncan Coutts
--
--  Created: 18 December 2008
--
--  Copyright (C) 2003-2008 Peter Gavin, Duncan Coutts, Axel Simon
--  Copyright (C) 2010 Andy Stewart
--
--  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 2.1 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.
--
-- |
-- Maintainer  : gtk2hs-users@lists.sourceforge.net
-- Stability   : provisional
-- Portability : portable (depends on GHC)
--
module Graphics.UI.Gtk.SourceView.SourceBuffer (
-- * Description
-- | The 'SourceBuffer' object is the model for 'SourceView' widgets. It extends the 'TextBuffer'
-- object by adding features useful to display and edit source code as syntax highlighting and bracket
-- matching. It also implements support for undo/redo operations.
--
-- To create a 'SourceBuffer' use 'sourceBufferNew' or
-- 'sourceBufferNewWithLanguage'. The second form is just a convenience function which allows
-- you to initially set a 'SourceLanguage'.
--
-- By default highlighting is enabled, but you can disable it with
-- 'sourceBufferSetHighlightSyntax'.

-- * Types
  SourceBuffer,
  SourceBufferClass,

-- * Methods
  castToSourceBuffer,
  sourceBufferNew,
  sourceBufferNewWithLanguage,
  sourceBufferSetHighlightSyntax,
  sourceBufferGetHighlightSyntax,
  sourceBufferSetLanguage,
  sourceBufferGetLanguage,
  sourceBufferSetHighlightMatchingBrackets,
  sourceBufferGetHighlightMatchingBrackets,
  sourceBufferSetStyleScheme,
  sourceBufferGetStyleScheme,
  sourceBufferSetMaxUndoLevels,
  sourceBufferGetMaxUndoLevels,
  sourceBufferGetCanUndo,
  sourceBufferGetCanRedo,
  sourceBufferUndo,
  sourceBufferRedo,
  sourceBufferBeginNotUndoableAction,
  sourceBufferEndNotUndoableAction,
  sourceBufferCreateSourceMark,
  sourceBufferGetSourceMarksAtLine,
  sourceBufferGetSourceMarksAtIter,
  sourceBufferRemoveSourceMarks,
  sourceBufferForwardIterToSourceMark,
  sourceBufferBackwardIterToSourceMark,
  sourceBufferEnsureHighlight,

-- * Attributes
  sourceBufferCanRedo,
  sourceBufferCanUndo,
  sourceBufferHighlightMatchingBrackets,
  sourceBufferHighlightSyntax,
  sourceBufferLanguage,
  sourceBufferSourceStyleScheme,
  sourceBufferMaxUndoLevels,

-- * Signals
  sourceBufferHighlightUpdated,
  sourceBufferRedoSignal,
  sourceBufferUndoSignal,
  sourceBufferSourceMarkUpdated,
  ) where

import Control.Monad	(liftM)
import Data.Maybe    (fromMaybe)

import System.Glib.FFI
import System.Glib.GList
import System.Glib.GObject              (constructNewGObject,
					 makeNewGObject)
{#import System.Glib.Properties#}
import System.Glib.Attributes
import Graphics.UI.Gtk.Abstract.Object	(makeNewObject)
{#import Graphics.UI.Gtk.SourceView.Types#}
{#import Graphics.UI.Gtk.SourceView.Signals#}
{#import Graphics.UI.Gtk.Multiline.TextIter#}

{#import Graphics.UI.Gtk.SourceView.SourceMark#}

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

-- methods

-- | Create a new 'SourceBuffer', possibly
-- taking a 'TextTagTable'.
--
sourceBufferNew :: Maybe TextTagTable -> IO SourceBuffer
sourceBufferNew tt = constructNewGObject mkSourceBuffer $
  {#call unsafe source_buffer_new#}
  (fromMaybe (TextTagTable nullForeignPtr) tt)

-- | Create a new 'SourceBuffer'
-- with a 'SourceLanguage'.
--
sourceBufferNewWithLanguage :: SourceLanguage -> IO SourceBuffer
sourceBufferNewWithLanguage lang = constructNewGObject mkSourceBuffer $
  {#call unsafe source_buffer_new_with_language#} lang

-- | Controls whether syntax is highlighted in the buffer. If highlight is 'True', the text will be
-- highlighted according to the syntax patterns specified in the language set with
-- 'sourceBufferSetLanguage'. If highlight is 'False', syntax highlighting is disabled and all the
-- 'TextTag' objects that have been added by the syntax highlighting engine are removed from the
-- buffer.
sourceBufferSetHighlightSyntax :: SourceBufferClass buffer => buffer  -- ^ @buffer@    a 'SourceBuffer'.
                               -> Bool  -- ^ @highlight@ 'True' to enable syntax highlighting, 'False' to disable it.
                               -> IO ()
sourceBufferSetHighlightSyntax sb newVal =
  {#call unsafe source_buffer_set_highlight_syntax#}
    (toSourceBuffer sb)
    (fromBool newVal)

-- | Determines whether syntax highlighting is activated in the source buffer.
sourceBufferGetHighlightSyntax :: SourceBufferClass buffer => buffer
                               -> IO Bool  -- ^ returns 'True' if syntax highlighting is enabled, 'False' otherwise.
sourceBufferGetHighlightSyntax sb = liftM toBool $
  {#call unsafe source_buffer_get_highlight_syntax#}
    (toSourceBuffer sb)

-- | Associate a 'SourceLanguage' with the source buffer. If language is not-'Nothing' and syntax
-- highlighting is enabled (see 'sourceBufferSetHighlightSyntax', the syntax patterns defined
-- in language will be used to highlight the text contained in the buffer. If language is 'Nothing', the
-- text contained in the buffer is not highlighted.
sourceBufferSetLanguage :: SourceBufferClass buffer => buffer
                        -> Maybe SourceLanguage  -- ^ @language@ a 'SourceLanguage' to set, or 'Nothing'.
                        -> IO ()
sourceBufferSetLanguage sb lang =
  {#call unsafe source_buffer_set_language#}
    (toSourceBuffer sb)
    (fromMaybe (SourceLanguage nullForeignPtr) lang)

-- | Returns the 'SourceLanguage' associated with the buffer, see 'sourceBufferSetLanguage'.
sourceBufferGetLanguage :: SourceBufferClass buffer => buffer
                        -> IO (Maybe SourceLanguage) -- ^ returns 'SourceLanguage' associated with the buffer, or 'Nothing'.
sourceBufferGetLanguage sb =
  maybeNull (makeNewGObject mkSourceLanguage) $
  {#call unsafe source_buffer_get_language#} (toSourceBuffer sb)

-- | Controls the bracket match highlighting function in the buffer. If activated, when you position your
-- cursor over a bracket character (a parenthesis, a square bracket, etc.) the matching opening or
-- closing bracket character will be highlighted. You can specify the style with the
-- 'sourceBufferSetBracketMatchStyle' function.
sourceBufferSetHighlightMatchingBrackets :: SourceBufferClass buffer => buffer
                                         -> Bool  -- ^ @highlight@ 'True' if you want matching brackets highlighted.
                                         -> IO ()
sourceBufferSetHighlightMatchingBrackets sb newVal =
  {#call unsafe source_buffer_set_highlight_matching_brackets#} (toSourceBuffer sb) (fromBool newVal)

-- | Determines whether bracket match highlighting is activated for the source buffer.
sourceBufferGetHighlightMatchingBrackets :: SourceBufferClass buffer => buffer
                                         -> IO Bool  -- ^ returns 'True' if the source buffer will highlight matching brackets.
sourceBufferGetHighlightMatchingBrackets sb = liftM toBool $
  {#call unsafe source_buffer_get_highlight_matching_brackets#} (toSourceBuffer sb)

-- | Sets style scheme used by the buffer. If scheme is 'Nothing' no style scheme is used.
sourceBufferSetStyleScheme :: SourceBufferClass buffer => buffer
                           -> Maybe SourceStyleScheme  -- ^ @scheme@ style scheme.
                           -> IO ()
sourceBufferSetStyleScheme sb scheme =
    {#call unsafe source_buffer_set_style_scheme#}
      (toSourceBuffer sb)
      (fromMaybe (SourceStyleScheme nullForeignPtr) scheme)

-- | Returns the 'SourceStyleScheme' currently used in buffer.
sourceBufferGetStyleScheme :: SourceBufferClass buffer => buffer
                           -> IO (Maybe SourceStyleScheme) -- ^ returns the 'SourceStyleScheme' set by 'sourceBufferSetStyleScheme', or 'Nothing'.
sourceBufferGetStyleScheme sb =
    maybeNull (makeNewGObject mkSourceStyleScheme) $
    {#call unsafe source_buffer_get_style_scheme#} (toSourceBuffer sb)

-- | Sets the number of undo levels for user actions the buffer will track. If the number of user actions
-- exceeds the limit set by this function, older actions will be discarded.
--
-- If @maxUndoLevels@ is -1, no limit is set.
--
-- A new action is started whenever the function 'textBufferBeginUserAction' is called. In
-- general, this happens whenever the user presses any key which modifies the buffer, but the undo
-- manager will try to merge similar consecutive actions, such as multiple character insertions into
-- one action. But, inserting a newline does start a new action.
sourceBufferSetMaxUndoLevels :: SourceBufferClass buffer => buffer
                             -> Int  -- ^ @maxUndoLevels@ the desired maximum number of undo levels.
                             -> IO ()
sourceBufferSetMaxUndoLevels sb newVal =
  {#call unsafe source_buffer_set_max_undo_levels#} (toSourceBuffer sb) (fromIntegral newVal)

-- | Determines the number of undo levels the buffer will track for buffer edits.
sourceBufferGetMaxUndoLevels :: SourceBufferClass buffer => buffer
                             -> IO Int -- ^ returns the maximum number of possible undo levels or -1 if no limit is set.
sourceBufferGetMaxUndoLevels sb = liftM fromIntegral $
  {#call unsafe source_buffer_get_max_undo_levels#} (toSourceBuffer sb)

-- | Determines whether a source buffer can undo the last action.
sourceBufferGetCanUndo :: SourceBufferClass buffer => buffer
                       -> IO Bool -- ^ returns 'True' if it's possible to undo the last action.
sourceBufferGetCanUndo sb = liftM toBool $
  {#call unsafe source_buffer_can_undo#} (toSourceBuffer sb)

-- | Determines whether a source buffer can redo the last action (i.e. if the last operation was an
-- undo).
sourceBufferGetCanRedo :: SourceBufferClass buffer => buffer
                       -> IO Bool -- ^ returns 'True' if a redo is possible.
sourceBufferGetCanRedo sb = liftM toBool $
  {#call unsafe source_buffer_can_redo#} (toSourceBuffer sb)

-- | Undoes the last user action which modified the buffer. Use 'sourceBufferCanUndo' to check
-- whether a call to this function will have any effect.
--
-- Actions are defined as groups of operations between a call to 'textBufferBeginUserAction'
-- and 'textBufferEndUserAction' on the
-- same line.
sourceBufferUndo :: SourceBufferClass buffer => buffer -> IO ()
sourceBufferUndo sb =
  {#call source_buffer_undo#} (toSourceBuffer sb)

-- | Redoes the last undo operation. Use 'sourceBufferCanRedo' to check whether a call to this
-- function will have any effect.
sourceBufferRedo :: SourceBufferClass buffer => buffer -> IO ()
sourceBufferRedo sb =
  {#call source_buffer_redo#} (toSourceBuffer sb)

-- | Marks the beginning of a not undoable action on the buffer, disabling the undo manager. Typically
-- you would call this function before initially setting the contents of the buffer (e.g. when loading
-- a file in a text editor).
--
-- You may nest 'sourceBufferBeginNotUndoableAction' /
-- 'sourceBufferEndNotUndoableAction' blocks.
sourceBufferBeginNotUndoableAction :: SourceBufferClass buffer => buffer -> IO ()
sourceBufferBeginNotUndoableAction sb =
  {#call source_buffer_begin_not_undoable_action#} (toSourceBuffer sb)

-- | Marks the end of a not undoable action on the buffer. When the last not undoable block is closed
-- through the call to this function, the list of undo actions is cleared and the undo manager is
-- re-enabled.
sourceBufferEndNotUndoableAction :: SourceBufferClass buffer => buffer -> IO ()
sourceBufferEndNotUndoableAction sb =
  {#call source_buffer_end_not_undoable_action#} (toSourceBuffer sb)

-- | Creates a marker in the buffer of the given type.
--
-- *  A marker is
--    semantically very similar to a 'Graphics.UI.Gtk.Multiline.TextMark',
--    except it has a type
--    which is used by the 'SourceView' displaying the buffer to show a
--    pixmap on the left margin, at the line the marker is in.  Because
--    of this, a marker is generally associated to a line and not a
--    character position.  Markers are also accessible through a position
--    or range in the buffer.
--
-- *  Markers are implemented using 'Graphics.UI.Gtk.Multiline.TextMark',
--    so all characteristics
--    and restrictions to marks apply to markers too.  These includes
--    life cycle issues and 'Graphics.UI.Gtk.Multiline.TextMark.onMarkSet'
--    and 'Graphics.UI.Gtk.Multiline.TextMark.onMarkDeleted' signal
--    emissions.
--
-- *  Like a 'Graphics.UI.Gtk.Multiline.TextMark', a 'SourceMarker'
--    can be anonymous if the
--    passed name is @Nothing@.  Also, the buffer owns the markers so you
--    shouldn't unreference it.

sourceBufferCreateSourceMark :: SourceBufferClass buffer => buffer -- the buffer
                         -> Maybe String -- the name of the mark
                         -> String -- the category of the mark
                         -> TextIter -> IO SourceMark
sourceBufferCreateSourceMark sb name category iter =
  makeNewGObject mkSourceMark $
  maybeWith withCString name       $ \strPtr1 ->
  withCString category $ \strPtr2 ->
  {#call source_buffer_create_source_mark#} (toSourceBuffer sb) strPtr1 strPtr2 iter

-- | Returns the list of marks of the given category at line. If category is empty, all marks at line are
-- returned.
sourceBufferGetSourceMarksAtLine :: SourceBufferClass buffer => buffer  -- ^ @buffer@   a 'SourceBuffer'.
                                 -> Int -- ^ @line@     a line number.
                                 -> String -- ^ @category@ category to search for or empty
                                 -> IO [SourceMark]
sourceBufferGetSourceMarksAtLine buffer line category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_get_source_marks_at_line #}
    (toSourceBuffer buffer)
    (fromIntegral line)
    categoryPtr
  >>= readGSList
  >>= mapM (\markPtr -> makeNewGObject mkSourceMark (return markPtr))

-- | Returns the list of marks of the given category at iter. If category is empty it returns all marks at
-- iter.
sourceBufferGetSourceMarksAtIter :: SourceBufferClass buffer => buffer -- ^ @buffer@   a 'SourceBuffer'.
                                 -> TextIter -- ^ @iter@     an iterator.
                                 -> String -- ^ @category@ category to search for or empty
                                 -> IO [SourceMark]
sourceBufferGetSourceMarksAtIter buffer iter category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_get_source_marks_at_iter #}
    (toSourceBuffer buffer)
    iter
    categoryPtr
  >>= readGSList
  >>= mapM (\markPtr -> makeNewGObject mkSourceMark (return markPtr))

-- | Remove all marks of category between start and end from the buffer. If category is empty, all marks
-- in the range will be removed.
sourceBufferRemoveSourceMarks :: SourceBufferClass buffer => buffer -- ^ @buffer@   a 'SourceBuffer'.
                              -> TextIter -- ^ @start@    a 'TextIter'
                              -> TextIter -- ^ @end@      a 'TextIter'
                              -> String -- ^ @category@ category to search for or empty
                              -> IO ()
sourceBufferRemoveSourceMarks buffer start end category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_remove_source_marks #}
     (toSourceBuffer buffer)
     start
     end
     categoryPtr

-- | Moves iter to the position of the next 'SourceMark' of the given category. Returns 'True' if iter was
-- moved. If category is empty, the next source mark can be of any category.
sourceBufferForwardIterToSourceMark :: SourceBufferClass buffer => buffer -- ^ @buffer@   a 'SourceBuffer'.
                                    -> TextIter -- ^ @iter@     an iterator.
                                    -> String -- ^ @category@ category to search for or emtpy
                                    -> IO Bool -- ^ returns  whether iter moved.
sourceBufferForwardIterToSourceMark buffer iter category =
  liftM toBool $
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_forward_iter_to_source_mark #}
    (toSourceBuffer buffer)
    iter
    categoryPtr

-- | Moves iter to the position of the previous 'SourceMark' of the given category. Returns 'True' if iter
-- was moved. If category is empty, the previous source mark can be of any category.
sourceBufferBackwardIterToSourceMark :: SourceBufferClass buffer => buffer  -- ^ @buffer@   a 'SourceBuffer'.
                                     -> TextIter -- ^ @iter@     an iterator.
                                     -> String -- ^ @category@ category to search for or emtpy
                                     -> IO Bool -- ^ returns  whether iter moved.
sourceBufferBackwardIterToSourceMark buffer iter category =
  liftM toBool $
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_backward_iter_to_source_mark #}
    (toSourceBuffer buffer)
    iter
    categoryPtr

-- | Forces buffer to analyze and highlight the given area synchronously.
--
-- Note
--
-- This is a potentially slow operation and should be used only when you need to make sure that some
-- text not currently visible is highlighted, for instance before printing.
sourceBufferEnsureHighlight :: SourceBufferClass buffer => buffer
                            -> TextIter  -- ^ @start@  start of the area to highlight.
                            -> TextIter  -- ^ @end@    end of the area to highlight.
                            -> IO ()
sourceBufferEnsureHighlight sb start end =
    {#call source_buffer_ensure_highlight#} (toSourceBuffer sb) start end

-- | Whether Redo operation is possible.
--
-- Default value: 'False'
--
sourceBufferCanRedo :: SourceBufferClass buffer => ReadAttr buffer Bool
sourceBufferCanRedo = readAttrFromBoolProperty "can-redo"

-- | Whether Undo operation is possible.
--
-- Default value: 'False'
sourceBufferCanUndo :: SourceBufferClass buffer => ReadAttr buffer Bool
sourceBufferCanUndo = readAttrFromBoolProperty "can-undo"

-- | Whether to highlight matching brackets in the buffer.
--
-- Default value: 'True'
--
sourceBufferHighlightMatchingBrackets :: SourceBufferClass buffer => Attr buffer Bool
sourceBufferHighlightMatchingBrackets = newAttrFromBoolProperty "highlight-matching-brackets"

-- | Whether to highlight syntax in the buffer.
--
-- Default value: 'True'
--
sourceBufferHighlightSyntax :: SourceBufferClass buffer => Attr buffer Bool
sourceBufferHighlightSyntax = newAttrFromBoolProperty "highlight-matching-brackets"

-- | Language object to get highlighting patterns from.
--
sourceBufferLanguage :: SourceBufferClass buffer => Attr buffer (Maybe SourceLanguage)
sourceBufferLanguage = newAttrFromMaybeObjectProperty "language" gTypeSourceLanguage

-- | Number of undo levels for the buffer. -1 means no limit. This property will only affect the default
-- undo manager.
--
-- Allowed values: >= GMaxulong
--
-- Default value: 1000
--
sourceBufferMaxUndoLevels :: SourceBufferClass buffer => Attr buffer Int
sourceBufferMaxUndoLevels = newAttrFromIntProperty "max-undo-levels"

-- | Style scheme. It contains styles for syntax highlighting, optionally foreground, background, cursor
-- color, current line color, and matching brackets style.
--
sourceBufferSourceStyleScheme :: SourceBufferClass buffer => Attr buffer (Maybe SourceStyleScheme)
sourceBufferSourceStyleScheme = newAttrFromMaybeObjectProperty "style-scheme" gTypeSourceStyleScheme

-- |
--
sourceBufferHighlightUpdated :: SourceBufferClass buffer => Signal buffer (TextIter -> TextIter -> IO ())
sourceBufferHighlightUpdated = Signal $ connect_BOXED_BOXED__NONE "highlight-updated" mkTextIterCopy mkTextIterCopy

-- |
--
sourceBufferRedoSignal :: SourceBufferClass buffer => Signal buffer (IO ())
sourceBufferRedoSignal = Signal $ connect_NONE__NONE "redo"

-- |
--
sourceBufferUndoSignal :: SourceBufferClass buffer => Signal buffer (IO ())
sourceBufferUndoSignal = Signal $ connect_NONE__NONE "undo"

-- | The 'sourceBufferMarkUpdated' signal is emitted each time a mark is added to, moved or removed from the
-- buffer.
--
sourceBufferSourceMarkUpdated :: SourceBufferClass buffer => Signal buffer (TextMark -> IO ())
sourceBufferSourceMarkUpdated = Signal $ connect_OBJECT__NONE "source-mark-updated"

{-# LANGUAGE CPP #-}
-- -*-haskell-*-
--  GIMP Toolkit (GTK) SourceBuffer
--
--  Author : Peter Gavin, Andy Stewart
--  derived from sourceview bindings by Axel Simon and Duncan Coutts
--
--  Created: 18 December 2008
--
--  Copyright (C) 2003-2008 Peter Gavin, Duncan Coutts, Axel Simon
--  Copyright (C) 2010 Andy Stewart
--
--  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 2.1 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.
--
-- |
-- Maintainer  : gtk2hs-users@lists.sourceforge.net
-- Stability   : provisional
-- Portability : portable (depends on GHC)
--
module Graphics.UI.Gtk.SourceView.SourceBuffer (
-- * Types
  SourceBuffer,
  SourceBufferClass,

-- * Methods
  castToSourceBuffer,
  sourceBufferNew,
  sourceBufferNewWithLanguage,
  sourceBufferSetHighlightSyntax,
  sourceBufferGetHighlightSyntax,
  sourceBufferSetLanguage,
  sourceBufferGetLanguage,
  sourceBufferSetHighlightMatchingBrackets,
  sourceBufferGetHighlightMatchingBrackets,
  sourceBufferSetStyleScheme,
  sourceBufferGetStyleScheme,
  sourceBufferSetMaxUndoLevels,
  sourceBufferGetMaxUndoLevels,
  sourceBufferGetCanUndo,
  sourceBufferGetCanRedo,
  sourceBufferUndo,
  sourceBufferRedo,
  sourceBufferBeginNotUndoableAction,
  sourceBufferEndNotUndoableAction,
  sourceBufferCreateSourceMark,
  sourceBufferGetSourceMarksAtLine,
  sourceBufferGetSourceMarksAtIter,
  sourceBufferRemoveSourceMarks,
  sourceBufferForwardIterToSourceMark,
  sourceBufferBackwardIterToSourceMark,
  sourceBufferEnsureHighlight,

-- * Attributes
  sourceBufferCanRedo,
  sourceBufferCanUndo,
  sourceBufferHighlightMatchingBrackets,
  sourceBufferHighlightSyntax,
  sourceBufferLanguage,
  sourceBufferSourceStyleScheme,
  sourceBufferMaxUndoLevels,

-- * Signals
  sourceBufferHighlightUpdated,
  sourceBufferRedoSignal,
  sourceBufferUndoSignal,
  sourceBufferSourceMarkUpdated,
  ) where

import Control.Monad	(liftM)
import Data.Maybe    (fromMaybe)

import System.Glib.FFI
import System.Glib.GList
import System.Glib.GObject              (constructNewGObject,
					 makeNewGObject)
{#import System.Glib.Properties#}
import System.Glib.Attributes
import Graphics.UI.Gtk.Abstract.Object	(makeNewObject)
{#import Graphics.UI.Gtk.SourceView.Types#}
{#import Graphics.UI.Gtk.SourceView.Signals#}
{#import Graphics.UI.Gtk.Multiline.TextIter#}

{#import Graphics.UI.Gtk.SourceView.SourceMark#}

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

-- methods

-- | Create a new 'SourceBuffer', possibly
-- taking a 'TextTagTable'.
--
sourceBufferNew :: Maybe TextTagTable -> IO SourceBuffer
sourceBufferNew tt = constructNewGObject mkSourceBuffer $
  {#call unsafe source_buffer_new#}
  (fromMaybe (TextTagTable nullForeignPtr) tt)

-- | Create a new 'SourceBuffer'
-- with a 'SourceLanguage'.
--
sourceBufferNewWithLanguage :: SourceLanguage -> IO SourceBuffer
sourceBufferNewWithLanguage lang = constructNewGObject mkSourceBuffer $
  {#call unsafe source_buffer_new_with_language#} lang

-- | Controls whether syntax is highlighted in the buffer. If highlight is 'True', the text will be
-- highlighted according to the syntax patterns specified in the language set with
-- 'sourceBufferSetLanguage'. If highlight is 'False', syntax highlighting is disabled and all the
-- 'TextTag' objects that have been added by the syntax highlighting engine are removed from the
-- buffer.
sourceBufferSetHighlightSyntax :: SourceBufferClass buffer => buffer  -- ^ @buffer@    a 'SourceBuffer'.
                               -> Bool  -- ^ @highlight@ 'True' to enable syntax highlighting, 'False' to disable it.
                               -> IO ()
sourceBufferSetHighlightSyntax sb newVal =
  {#call unsafe source_buffer_set_highlight_syntax#}
    (toSourceBuffer sb)
    (fromBool newVal)

-- | Determines whether syntax highlighting is activated in the source buffer.
sourceBufferGetHighlightSyntax :: SourceBufferClass buffer => buffer
                               -> IO Bool  -- ^ returns 'True' if syntax highlighting is enabled, 'False' otherwise.
sourceBufferGetHighlightSyntax sb = liftM toBool $
  {#call unsafe source_buffer_get_highlight_syntax#}
    (toSourceBuffer sb)

-- | Associate a 'SourceLanguage' with the source buffer. If language is not-'Nothing' and syntax
-- highlighting is enabled (see 'sourceBufferSetHighlightSyntax', the syntax patterns defined
-- in language will be used to highlight the text contained in the buffer. If language is 'Nothing', the
-- text contained in the buffer is not highlighted.
sourceBufferSetLanguage :: SourceBufferClass buffer => buffer
                        -> Maybe SourceLanguage  -- ^ @language@ a 'SourceLanguage' to set, or 'Nothing'.
                        -> IO ()
sourceBufferSetLanguage sb lang =
  {#call unsafe source_buffer_set_language#}
    (toSourceBuffer sb)
    (fromMaybe (SourceLanguage nullForeignPtr) lang)

-- | Returns the 'SourceLanguage' associated with the buffer, see 'sourceBufferSetLanguage'.
sourceBufferGetLanguage :: SourceBufferClass buffer => buffer
                        -> IO (Maybe SourceLanguage) -- ^ returns 'SourceLanguage' associated with the buffer, or 'Nothing'.
sourceBufferGetLanguage sb =
  maybeNull (makeNewGObject mkSourceLanguage) $
  {#call unsafe source_buffer_get_language#} (toSourceBuffer sb)

-- | Controls the bracket match highlighting function in the buffer. If activated, when you position your
-- cursor over a bracket character (a parenthesis, a square bracket, etc.) the matching opening or
-- closing bracket character will be highlighted. You can specify the style with the
-- 'sourceBufferSetBracketMatchStyle' function.
sourceBufferSetHighlightMatchingBrackets :: SourceBufferClass buffer => buffer
                                         -> Bool  -- ^ @highlight@ 'True' if you want matching brackets highlighted.
                                         -> IO ()
sourceBufferSetHighlightMatchingBrackets sb newVal =
  {#call unsafe source_buffer_set_highlight_matching_brackets#} (toSourceBuffer sb) (fromBool newVal)

-- | Determines whether bracket match highlighting is activated for the source buffer.
sourceBufferGetHighlightMatchingBrackets :: SourceBufferClass buffer => buffer
                                         -> IO Bool  -- ^ returns 'True' if the source buffer will highlight matching brackets.
sourceBufferGetHighlightMatchingBrackets sb = liftM toBool $
  {#call unsafe source_buffer_get_highlight_matching_brackets#} (toSourceBuffer sb)

-- | Sets style scheme used by the buffer. If scheme is 'Nothing' no style scheme is used.
sourceBufferSetStyleScheme :: SourceBufferClass buffer => buffer
                           -> Maybe SourceStyleScheme  -- ^ @scheme@ style scheme.
                           -> IO ()
sourceBufferSetStyleScheme sb scheme =
    {#call unsafe source_buffer_set_style_scheme#}
      (toSourceBuffer sb)
      (fromMaybe (SourceStyleScheme nullForeignPtr) scheme)

-- | Returns the 'SourceStyleScheme' currently used in buffer.
sourceBufferGetStyleScheme :: SourceBufferClass buffer => buffer
                           -> IO (Maybe SourceStyleScheme) -- ^ returns the 'SourceStyleScheme' set by 'sourceBufferSetStyleScheme', or 'Nothing'.
sourceBufferGetStyleScheme sb =
    maybeNull (makeNewGObject mkSourceStyleScheme) $
    {#call unsafe source_buffer_get_style_scheme#} (toSourceBuffer sb)

-- | Sets the number of undo levels for user actions the buffer will track. If the number of user actions
-- exceeds the limit set by this function, older actions will be discarded.
--
-- If @maxUndoLevels@ is -1, no limit is set.
--
-- A new action is started whenever the function 'textBufferBeginUserAction' is called. In
-- general, this happens whenever the user presses any key which modifies the buffer, but the undo
-- manager will try to merge similar consecutive actions, such as multiple character insertions into
-- one action. But, inserting a newline does start a new action.
sourceBufferSetMaxUndoLevels :: SourceBufferClass buffer => buffer
                             -> Int  -- ^ @maxUndoLevels@ the desired maximum number of undo levels.
                             -> IO ()
sourceBufferSetMaxUndoLevels sb newVal =
  {#call unsafe source_buffer_set_max_undo_levels#} (toSourceBuffer sb) (fromIntegral newVal)

-- | Determines the number of undo levels the buffer will track for buffer edits.
sourceBufferGetMaxUndoLevels :: SourceBufferClass buffer => buffer
                             -> IO Int -- ^ returns the maximum number of possible undo levels or -1 if no limit is set.
sourceBufferGetMaxUndoLevels sb = liftM fromIntegral $
  {#call unsafe source_buffer_get_max_undo_levels#} (toSourceBuffer sb)

-- | Determines whether a source buffer can undo the last action.
sourceBufferGetCanUndo :: SourceBufferClass buffer => buffer
                       -> IO Bool -- ^ returns 'True' if it's possible to undo the last action.
sourceBufferGetCanUndo sb = liftM toBool $
  {#call unsafe source_buffer_can_undo#} (toSourceBuffer sb)

-- | Determines whether a source buffer can redo the last action (i.e. if the last operation was an
-- undo).
sourceBufferGetCanRedo :: SourceBufferClass buffer => buffer
                       -> IO Bool -- ^ returns 'True' if a redo is possible.
sourceBufferGetCanRedo sb = liftM toBool $
  {#call unsafe source_buffer_can_redo#} (toSourceBuffer sb)

-- | Undoes the last user action which modified the buffer. Use 'sourceBufferCanUndo' to check
-- whether a call to this function will have any effect.
--
-- Actions are defined as groups of operations between a call to 'textBufferBeginUserAction'
-- and 'textBufferEndUserAction' on the
-- same line.
sourceBufferUndo :: SourceBufferClass buffer => buffer -> IO ()
sourceBufferUndo sb =
  {#call source_buffer_undo#} (toSourceBuffer sb)

-- | Redoes the last undo operation. Use 'sourceBufferCanRedo' to check whether a call to this
-- function will have any effect.
sourceBufferRedo :: SourceBufferClass buffer => buffer -> IO ()
sourceBufferRedo sb =
  {#call source_buffer_redo#} (toSourceBuffer sb)

-- | Marks the beginning of a not undoable action on the buffer, disabling the undo manager. Typically
-- you would call this function before initially setting the contents of the buffer (e.g. when loading
-- a file in a text editor).
--
-- You may nest 'sourceBufferBeginNotUndoableAction' /
-- 'sourceBufferEndNotUndoableAction' blocks.
sourceBufferBeginNotUndoableAction :: SourceBufferClass buffer => buffer -> IO ()
sourceBufferBeginNotUndoableAction sb =
  {#call source_buffer_begin_not_undoable_action#} (toSourceBuffer sb)

-- | Marks the end of a not undoable action on the buffer. When the last not undoable block is closed
-- through the call to this function, the list of undo actions is cleared and the undo manager is
-- re-enabled.
sourceBufferEndNotUndoableAction :: SourceBufferClass buffer => buffer -> IO ()
sourceBufferEndNotUndoableAction sb =
  {#call source_buffer_end_not_undoable_action#} (toSourceBuffer sb)

-- | Creates a marker in the buffer of the given type.
--
-- *  A marker is
--    semantically very similar to a 'Graphics.UI.Gtk.Multiline.TextMark',
--    except it has a type
--    which is used by the 'SourceView' displaying the buffer to show a
--    pixmap on the left margin, at the line the marker is in.  Because
--    of this, a marker is generally associated to a line and not a
--    character position.  Markers are also accessible through a position
--    or range in the buffer.
--
-- *  Markers are implemented using 'Graphics.UI.Gtk.Multiline.TextMark',
--    so all characteristics
--    and restrictions to marks apply to markers too.  These includes
--    life cycle issues and 'Graphics.UI.Gtk.Multiline.TextMark.onMarkSet'
--    and 'Graphics.UI.Gtk.Multiline.TextMark.onMarkDeleted' signal
--    emissions.
--
-- *  Like a 'Graphics.UI.Gtk.Multiline.TextMark', a 'SourceMarker'
--    can be anonymous if the
--    passed name is @Nothing@.  Also, the buffer owns the markers so you
--    shouldn't unreference it.

sourceBufferCreateSourceMark :: SourceBufferClass buffer => buffer -- the buffer
                         -> Maybe String -- the name of the mark
                         -> String -- the category of the mark
                         -> TextIter -> IO SourceMark
sourceBufferCreateSourceMark sb name category iter =
  makeNewGObject mkSourceMark $
  maybeWith withCString name       $ \strPtr1 ->
  withCString category $ \strPtr2 ->
  {#call source_buffer_create_source_mark#} (toSourceBuffer sb) strPtr1 strPtr2 iter

-- | Returns the list of marks of the given category at line. If category is empty, all marks at line are
-- returned.
sourceBufferGetSourceMarksAtLine :: SourceBufferClass buffer => buffer  -- ^ @buffer@   a 'SourceBuffer'.
                                 -> Int -- ^ @line@     a line number.
                                 -> String -- ^ @category@ category to search for or empty
                                 -> IO [SourceMark]
sourceBufferGetSourceMarksAtLine buffer line category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_get_source_marks_at_line #}
    (toSourceBuffer buffer)
    (fromIntegral line)
    categoryPtr
  >>= readGSList
  >>= mapM (\markPtr -> makeNewGObject mkSourceMark (return markPtr))

-- | Returns the list of marks of the given category at iter. If category is empty it returns all marks at
-- iter.
sourceBufferGetSourceMarksAtIter :: SourceBufferClass buffer => buffer -- ^ @buffer@   a 'SourceBuffer'.
                                 -> TextIter -- ^ @iter@     an iterator.
                                 -> String -- ^ @category@ category to search for or empty
                                 -> IO [SourceMark]
sourceBufferGetSourceMarksAtIter buffer iter category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_get_source_marks_at_iter #}
    (toSourceBuffer buffer)
    iter
    categoryPtr
  >>= readGSList
  >>= mapM (\markPtr -> makeNewGObject mkSourceMark (return markPtr))

-- | Remove all marks of category between start and end from the buffer. If category is empty, all marks
-- in the range will be removed.
sourceBufferRemoveSourceMarks :: SourceBufferClass buffer => buffer -- ^ @buffer@   a 'SourceBuffer'.
                              -> TextIter -- ^ @start@    a 'TextIter'
                              -> TextIter -- ^ @end@      a 'TextIter'
                              -> String -- ^ @category@ category to search for or empty
                              -> IO ()
sourceBufferRemoveSourceMarks buffer start end category =
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_remove_source_marks #}
     (toSourceBuffer buffer)
     start
     end
     categoryPtr

-- | Moves iter to the position of the next 'SourceMark' of the given category. Returns 'True' if iter was
-- moved. If category is empty, the next source mark can be of any category.
sourceBufferForwardIterToSourceMark :: SourceBufferClass buffer => buffer -- ^ @buffer@   a 'SourceBuffer'.
                                    -> TextIter -- ^ @iter@     an iterator.
                                    -> String -- ^ @category@ category to search for or emtpy
                                    -> IO Bool -- ^ returns  whether iter moved.
sourceBufferForwardIterToSourceMark buffer iter category =
  liftM toBool $
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_forward_iter_to_source_mark #}
    (toSourceBuffer buffer)
    iter
    categoryPtr

-- | Moves iter to the position of the previous 'SourceMark' of the given category. Returns 'True' if iter
-- was moved. If category is empty, the previous source mark can be of any category.
sourceBufferBackwardIterToSourceMark :: SourceBufferClass buffer => buffer  -- ^ @buffer@   a 'SourceBuffer'.
                                     -> TextIter -- ^ @iter@     an iterator.
                                     -> String -- ^ @category@ category to search for or emtpy
                                     -> IO Bool -- ^ returns  whether iter moved.
sourceBufferBackwardIterToSourceMark buffer iter category =
  liftM toBool $
  withCString category $ \categoryPtr ->
  {#call gtk_source_buffer_backward_iter_to_source_mark #}
    (toSourceBuffer buffer)
    iter
    categoryPtr

-- | Forces buffer to analyze and highlight the given area synchronously.
--
-- Note
--
-- This is a potentially slow operation and should be used only when you need to make sure that some
-- text not currently visible is highlighted, for instance before printing.
sourceBufferEnsureHighlight :: SourceBufferClass buffer => buffer
                            -> TextIter  -- ^ @start@  start of the area to highlight.
                            -> TextIter  -- ^ @end@    end of the area to highlight.
                            -> IO ()
sourceBufferEnsureHighlight sb start end =
    {#call source_buffer_ensure_highlight#} (toSourceBuffer sb) start end

-- | Whether Redo operation is possible.
--
-- Default value: 'False'
--
sourceBufferCanRedo :: SourceBufferClass buffer => ReadAttr buffer Bool
sourceBufferCanRedo = readAttrFromBoolProperty "can-redo"

-- | Whether Undo operation is possible.
--
-- Default value: 'False'
sourceBufferCanUndo :: SourceBufferClass buffer => ReadAttr buffer Bool
sourceBufferCanUndo = readAttrFromBoolProperty "can-undo"

-- | Whether to highlight matching brackets in the buffer.
--
-- Default value: 'True'
--
sourceBufferHighlightMatchingBrackets :: SourceBufferClass buffer => Attr buffer Bool
sourceBufferHighlightMatchingBrackets = newAttrFromBoolProperty "highlight-matching-brackets"

-- | Whether to highlight syntax in the buffer.
--
-- Default value: 'True'
--
sourceBufferHighlightSyntax :: SourceBufferClass buffer => Attr buffer Bool
sourceBufferHighlightSyntax = newAttrFromBoolProperty "highlight-matching-brackets"

-- | Language object to get highlighting patterns from.
--
sourceBufferLanguage :: SourceBufferClass buffer => Attr buffer (Maybe SourceLanguage)
sourceBufferLanguage = newAttrFromMaybeObjectProperty "language" gTypeSourceLanguage

-- | Number of undo levels for the buffer. -1 means no limit. This property will only affect the default
-- undo manager.
--
-- Allowed values: >= GMaxulong
--
-- Default value: 1000
--
sourceBufferMaxUndoLevels :: SourceBufferClass buffer => Attr buffer Int
sourceBufferMaxUndoLevels = newAttrFromIntProperty "max-undo-levels"

-- | Style scheme. It contains styles for syntax highlighting, optionally foreground, background, cursor
-- color, current line color, and matching brackets style.
--
sourceBufferSourceStyleScheme :: SourceBufferClass buffer => Attr buffer (Maybe SourceStyleScheme)
sourceBufferSourceStyleScheme = newAttrFromMaybeObjectProperty "style-scheme" gTypeSourceStyleScheme

-- |
--
sourceBufferHighlightUpdated :: SourceBufferClass buffer => Signal buffer (TextIter -> TextIter -> IO ())
sourceBufferHighlightUpdated = Signal $ connect_BOXED_BOXED__NONE "highlight-updated" mkTextIterCopy mkTextIterCopy

-- |
--
sourceBufferRedoSignal :: SourceBufferClass buffer => Signal buffer (IO ())
sourceBufferRedoSignal = Signal $ connect_NONE__NONE "redo"

-- |
--
sourceBufferUndoSignal :: SourceBufferClass buffer => Signal buffer (IO ())
sourceBufferUndoSignal = Signal $ connect_NONE__NONE "undo"

-- | The 'sourceBufferMarkUpdated' signal is emitted each time a mark is added to, moved or removed from the
-- buffer.
--
sourceBufferSourceMarkUpdated :: SourceBufferClass buffer => Signal buffer (TextMark -> IO ())
sourceBufferSourceMarkUpdated = Signal $ connect_OBJECT__NONE "source-mark-updated"