packages feed

simple-cairo-0.1.0.5: src/Graphics/Cairo/Drawing/CairoPatternT/Basic.hsc

{-# LANGUAGE BlockArguments, LambdaCase #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Graphics.Cairo.Drawing.CairoPatternT.Basic where

import Foreign.Ptr
import Foreign.ForeignPtr hiding (newForeignPtr)
import Foreign.Concurrent
import Foreign.Marshal
import Foreign.Storable
import Foreign.C.Types
import Control.Monad.Primitive
import Data.Traversable
import Data.Maybe
import Data.Word
import Data.Color
import System.IO.Unsafe

import Graphics.Cairo.Exception
import Graphics.Cairo.Surfaces.CairoSurfaceT.Internal

#include <cairo.h>

class IsCairoPatternT pt where toCairoPatternT :: pt s -> CairoPatternT s

newtype CairoPatternT s = CairoPatternT (ForeignPtr (CairoPatternT s)) deriving Show

instance IsCairoPatternT CairoPatternT where toCairoPatternT = id

makeCairoPatternT :: Ptr (CairoPatternT s) -> IO (CairoPatternT s)
makeCairoPatternT p = CairoPatternT <$> newForeignPtr p (c_cairo_pattern_destroy p)

returnCairoPatternT :: PrimMonad m => IO (Ptr (CairoPatternT (PrimState m))) -> m (CairoPatternT (PrimState m))
returnCairoPatternT io = unsafeIOToPrim $ makeCairoPatternT =<< io

foreign import ccall "cairo_pattern_destroy" c_cairo_pattern_destroy ::
	Ptr (CairoPatternT s) -> IO ()

newtype CairoPatternTypeT = CairoPatternTypeT #{type cairo_pattern_type_t} deriving Show

pattern CairoPatternTypeSolid :: CairoPatternTypeT
pattern CairoPatternTypeSolid <- CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_SOLID} where
	CairoPatternTypeSolid = CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_SOLID}

pattern CairoPatternTypeSurface :: CairoPatternTypeT
pattern CairoPatternTypeSurface <- CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_SURFACE} where
	CairoPatternTypeSurface = CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_SURFACE}

pattern CairoPatternTypeLinear :: CairoPatternTypeT
pattern CairoPatternTypeLinear <- CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_LINEAR} where
	CairoPatternTypeLinear = CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_LINEAR}

pattern CairoPatternTypeRadial :: CairoPatternTypeT
pattern CairoPatternTypeRadial <- CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_RADIAL} where
	CairoPatternTypeRadial = CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_RADIAL}

pattern CairoPatternTypeMesh :: CairoPatternTypeT
pattern CairoPatternTypeMesh <- CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_MESH} where
	CairoPatternTypeMesh = CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_MESH}

pattern CairoPatternTypeRasterSource :: CairoPatternTypeT
pattern CairoPatternTypeRasterSource <- CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_RASTER_SOURCE} where
	CairoPatternTypeRasterSource = CairoPatternTypeT #{const CAIRO_PATTERN_TYPE_RASTER_SOURCE}

cairoPatternGetType :: CairoPatternT s -> CairoPatternTypeT
cairoPatternGetType (CairoPatternT fpt) = unsafePerformIO $ withForeignPtr fpt \pt ->
	CairoPatternTypeT <$> c_cairo_pattern_get_type pt

foreign import ccall "cairo_pattern_get_type" c_cairo_pattern_get_type ::
	Ptr (CairoPatternT s) -> IO #{type cairo_pattern_type_t}

newtype CairoPatternSolidT s = CairoPatternSolidT (ForeignPtr (CairoPatternT s)) deriving Show

instance IsCairoPatternT CairoPatternSolidT where toCairoPatternT = CairoPatternTSolid

pattern CairoPatternTSolid :: CairoPatternSolidT s -> CairoPatternT s
pattern CairoPatternTSolid pts <- (cairoPatternSolidT -> Just pts) where
	CairoPatternTSolid (CairoPatternSolidT pts) = CairoPatternT pts

cairoPatternSolidT :: CairoPatternT s -> Maybe (CairoPatternSolidT s)
cairoPatternSolidT pt@(CairoPatternT fpt) = case cairoPatternGetType pt of
	CairoPatternTypeSolid -> Just $ CairoPatternSolidT fpt
	_ -> Nothing

cairoPatternCreateRgb :: PrimMonad m => Rgb CDouble -> m (CairoPatternSolidT (PrimState m))
cairoPatternCreateRgb (RgbDouble r g b) = unsafeIOToPrim do
	ppt <- c_cairo_pattern_create_rgb r g b
	pt <- CairoPatternSolidT <$> newForeignPtr ppt (c_cairo_pattern_destroy ppt)
	pt <$ raiseIfErrorPattern (CairoPatternTSolid pt)

foreign import ccall "cairo_pattern_create_rgb" c_cairo_pattern_create_rgb ::
	CDouble -> CDouble -> CDouble -> IO (Ptr (CairoPatternT s))

cairoPatternCreateRgba :: PrimMonad m => Rgba CDouble -> m (CairoPatternSolidT (PrimState m))
cairoPatternCreateRgba (RgbaDouble r g b a) = unsafeIOToPrim do
	ppt <- c_cairo_pattern_create_rgba r g b a
	pt <- CairoPatternSolidT <$> newForeignPtr ppt (c_cairo_pattern_destroy ppt)
	pt <$ raiseIfErrorPattern (CairoPatternTSolid pt)

foreign import ccall "cairo_pattern_create_rgba" c_cairo_pattern_create_rgba ::
	CDouble -> CDouble -> CDouble -> CDouble -> IO (Ptr (CairoPatternT s))

cairoPatternGetRgba :: PrimMonad m => CairoPatternSolidT (PrimState m) -> m (Rgba CDouble)
cairoPatternGetRgba (CairoPatternSolidT fpts) = unsafeIOToPrim $ withForeignPtr fpts \pts ->
	alloca \r -> alloca \g -> alloca \b -> alloca \a -> do
		cairoStatusToThrowError =<< c_cairo_pattern_get_rgba pts r g b a
		rgbaDouble <$> peek r <*> peek g <*> peek b <*> peek a >>= \case
			Just rgba -> pure rgba
			Nothing -> error $ "(r, g, b, a) = " ++ show (r, g, b, a)

foreign import ccall "cairo_pattern_get_rgba" c_cairo_pattern_get_rgba ::
	Ptr (CairoPatternT s) ->
	Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble ->
	IO #{type cairo_status_t}

class IsCairoPatternT pt => IsCairoPatternGradientT pt where
	toCairoPatternGradientT :: pt s -> CairoPatternGradientT s

newtype CairoPatternGradientT s = CairoPatternGradientT (ForeignPtr (CairoPatternT s)) deriving Show

instance IsCairoPatternT CairoPatternGradientT where
	toCairoPatternT = CairoPatternTGradient

instance IsCairoPatternGradientT CairoPatternGradientT where
	toCairoPatternGradientT = id

pattern CairoPatternTGradient :: CairoPatternGradientT s -> CairoPatternT s
pattern CairoPatternTGradient ptg <- (cairoPatternGradientT -> Just ptg) where
	CairoPatternTGradient (CairoPatternGradientT ptg) = CairoPatternT ptg

cairoPatternGradientT :: CairoPatternT s -> Maybe (CairoPatternGradientT s)
cairoPatternGradientT pt@(CairoPatternT fpt) = case cairoPatternGetType pt of
	CairoPatternTypeLinear -> Just $ CairoPatternGradientT fpt
	CairoPatternTypeRadial -> Just $ CairoPatternGradientT fpt
	_ -> Nothing

cairoPatternAddColorStopRgb :: (PrimMonad m, IsCairoPatternGradientT pt) =>
	pt (PrimState m) -> CDouble -> Rgb CDouble -> m ()
cairoPatternAddColorStopRgb (toCairoPatternGradientT -> CairoPatternGradientT fpt) os (RgbDouble r g b) =
	unsafeIOToPrim $ withForeignPtr fpt \ppt -> c_cairo_pattern_add_color_stop_rgb ppt os r g b

foreign import ccall "cairo_pattern_add_color_stop_rgb" c_cairo_pattern_add_color_stop_rgb ::
	Ptr (CairoPatternT s) -> CDouble -> CDouble -> CDouble -> CDouble -> IO ()

cairoPatternAddColorStopRgba :: (PrimMonad m, IsCairoPatternGradientT pt) =>
	pt (PrimState m) -> CDouble -> Rgba CDouble -> m ()
cairoPatternAddColorStopRgba (toCairoPatternGradientT -> CairoPatternGradientT fpt) os (RgbaDouble r g b a) =
	unsafeIOToPrim $ withForeignPtr fpt \ppt -> c_cairo_pattern_add_color_stop_rgba ppt os r g b a

foreign import ccall "cairo_pattern_add_color_stop_rgba" c_cairo_pattern_add_color_stop_rgba ::
	Ptr (CairoPatternT s) -> CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> IO ()

newtype CairoPatternLinearT s = CairoPatternLinearT (ForeignPtr (CairoPatternT s)) deriving Show

instance IsCairoPatternGradientT CairoPatternLinearT where
	toCairoPatternGradientT = CairoPatternGradientTLinear

instance IsCairoPatternT CairoPatternLinearT where
	toCairoPatternT = CairoPatternTGradient . toCairoPatternGradientT

pattern CairoPatternGradientTLinear :: CairoPatternLinearT s -> CairoPatternGradientT s
pattern CairoPatternGradientTLinear ptl <- (cairoPatternGradientLinearT -> Just ptl) where
	CairoPatternGradientTLinear (CairoPatternLinearT ptl) = CairoPatternGradientT ptl

cairoPatternGradientLinearT :: CairoPatternGradientT s -> Maybe (CairoPatternLinearT s)
cairoPatternGradientLinearT pt@(CairoPatternGradientT fpt) = case cairoPatternGetType $ CairoPatternTGradient pt of
	CairoPatternTypeLinear -> Just $ CairoPatternLinearT fpt
	_ -> Nothing

cairoPatternCreateLinear :: PrimMonad m =>
	CDouble -> CDouble -> CDouble -> CDouble -> m (CairoPatternLinearT (PrimState m))
cairoPatternCreateLinear x0 y0 x1 y1 = unsafeIOToPrim
	$ CairoPatternLinearT <$> do
		p <- c_cairo_pattern_create_linear x0 y0 x1 y1
		newForeignPtr p $ c_cairo_pattern_destroy p

foreign import ccall "cairo_pattern_create_linear" c_cairo_pattern_create_linear ::
	CDouble -> CDouble -> CDouble -> CDouble -> IO (Ptr (CairoPatternT s))

cairoPatternGetLinearPoints :: PrimMonad m =>
	CairoPatternLinearT (PrimState m) -> m ((CDouble, CDouble), (CDouble, CDouble))
cairoPatternGetLinearPoints (CairoPatternLinearT fpt) = unsafeIOToPrim
	$ withForeignPtr fpt \ppt -> alloca \x0 -> alloca \y0 -> alloca \x1 -> alloca \y1 -> do
		cs <- c_cairo_pattern_get_linear_points ppt x0 y0 x1 y1
		cairoStatusToThrowError cs
		(,) <$> ((,) <$> peek x0 <*> peek y0) <*> ((,) <$> peek x1 <*> peek y1)

foreign import ccall "cairo_pattern_get_linear_points" c_cairo_pattern_get_linear_points ::
	Ptr (CairoPatternT s) -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> IO #{type cairo_status_t}

cairoPatternGetColorStopRgbaList :: (PrimMonad m, IsCairoPatternGradientT pt) =>
	pt (PrimState m) -> m [(CDouble, Rgba CDouble)]
cairoPatternGetColorStopRgbaList pt = cairoPatternGetColorStopCount pt >>= \n ->
	for [0 .. n - 1] \i -> cairoPatternGetColorStopRgba pt i

cairoPatternGetColorStopCount :: (PrimMonad m, IsCairoPatternGradientT pt) =>
	pt (PrimState m) -> m CInt
cairoPatternGetColorStopCount (toCairoPatternGradientT -> CairoPatternGradientT fpt) = unsafeIOToPrim
	$ withForeignPtr fpt \ppt -> alloca \n -> do
		cs <- c_cairo_pattern_get_color_stop_count ppt n
		cairoStatusToThrowError cs
		peek n

foreign import ccall "cairo_pattern_get_color_stop_count" c_cairo_pattern_get_color_stop_count ::
	Ptr (CairoPatternT s) -> Ptr CInt -> IO #{type cairo_status_t}

cairoPatternGetColorStopRgba :: (PrimMonad m, IsCairoPatternGradientT pt) =>
	pt (PrimState m) -> CInt -> m (CDouble, Rgba CDouble)
cairoPatternGetColorStopRgba (toCairoPatternGradientT -> CairoPatternGradientT fpt) i = unsafeIOToPrim
	$ withForeignPtr fpt \ppt -> alloca \os -> alloca \rd -> alloca \gr -> alloca \bl -> alloca \al -> do
		cs <- c_cairo_pattern_get_color_stop_rgba ppt i os rd gr bl al
		cairoStatusToThrowError cs
		(,) <$> peek os <*> ((\r g b a -> fromJust $ rgbaDouble r g b a) <$> peek rd <*> peek gr <*> peek bl <*> peek al)

foreign import ccall "cairo_pattern_get_color_stop_rgba" c_cairo_pattern_get_color_stop_rgba ::
	Ptr (CairoPatternT s) -> CInt ->
	Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> IO #{type cairo_status_t}

newtype CairoPatternRadialT s = CairoPatternRadialT (ForeignPtr (CairoPatternT s)) deriving Show

instance IsCairoPatternT CairoPatternRadialT where
	toCairoPatternT = CairoPatternTGradient . toCairoPatternGradientT

instance IsCairoPatternGradientT CairoPatternRadialT where
	toCairoPatternGradientT = CairoPatternGradientTRadial

pattern CairoPatternGradientTRadial :: CairoPatternRadialT s -> CairoPatternGradientT s
pattern CairoPatternGradientTRadial pt <- (cairoPatternGradientRadialT -> Just pt) where
	CairoPatternGradientTRadial (CairoPatternRadialT fpt) = CairoPatternGradientT fpt

cairoPatternGradientRadialT :: CairoPatternGradientT s -> Maybe (CairoPatternRadialT s)
cairoPatternGradientRadialT pt@(CairoPatternGradientT fpt) = case cairoPatternGetType $ CairoPatternTGradient pt of
	CairoPatternTypeRadial -> Just $ CairoPatternRadialT fpt
	_ -> Nothing

cairoPatternCreateRadial :: PrimMonad m =>
	CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> CDouble ->
	m (CairoPatternRadialT (PrimState m))
cairoPatternCreateRadial cx0 cy0 r0 cx1 cy1 r1 = unsafeIOToPrim
	$ CairoPatternRadialT <$> do
		p <- c_cairo_pattern_create_radial cx0 cy0 r0 cx1 cy1 r1
		newForeignPtr p $ c_cairo_pattern_destroy p

foreign import ccall "cairo_pattern_create_radial" c_cairo_pattern_create_radial ::
	CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> CDouble -> IO (Ptr (CairoPatternT s))

cairoPatternGetRadialCircles :: PrimMonad m =>
	CairoPatternRadialT (PrimState m) -> m ((CDouble, CDouble, CDouble), (CDouble, CDouble, CDouble))
cairoPatternGetRadialCircles (CairoPatternRadialT fpt) = unsafeIOToPrim
	$ withForeignPtr fpt \ppt -> alloca \x0 -> alloca \y0 -> alloca \r0 -> alloca \x1 -> alloca \y1 -> alloca \r1 -> do
		cs <- c_cairo_pattern_get_radial_circles ppt x0 y0 r0 x1 y1 r1
		cairoStatusToThrowError cs
		(,) <$> ((,,) <$> peek x0 <*> peek y0 <*> peek r0) <*> ((,,) <$> peek x1 <*> peek y1 <*> peek r1)

foreign import ccall "cairo_pattern_get_radial_circles" c_cairo_pattern_get_radial_circles ::
	Ptr (CairoPatternT s) ->
	Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> Ptr CDouble -> IO #{type cairo_status_t}

newtype CairoPatternSurfaceT s = CairoPatternSurfaceT (ForeignPtr (CairoPatternT s)) deriving Show

instance IsCairoPatternT CairoPatternSurfaceT where
	toCairoPatternT = CairoPatternTSurface

pattern CairoPatternTSurface :: CairoPatternSurfaceT s -> CairoPatternT s
pattern CairoPatternTSurface pt <- (cairoPatternTSurface -> Just pt) where
	CairoPatternTSurface (CairoPatternSurfaceT fpt) = CairoPatternT fpt

cairoPatternTSurface :: CairoPatternT s -> Maybe (CairoPatternSurfaceT s)
cairoPatternTSurface pt@(CairoPatternT fpt) = case cairoPatternGetType pt of
	CairoPatternTypeSurface -> Just $ CairoPatternSurfaceT fpt
	_ -> Nothing

cairoPatternCreateForSurface :: (PrimMonad m, IsCairoSurfaceT sr) =>
	sr s (PrimState m) -> m (CairoPatternSurfaceT (PrimState m))
cairoPatternCreateForSurface (toCairoSurfaceT -> CairoSurfaceT fs) =
	unsafeIOToPrim $ CairoPatternSurfaceT <$> withForeignPtr fs \ps -> do
		p <- c_cairo_pattern_create_for_surface ps
		newForeignPtr p $ touchForeignPtr fs >> c_cairo_pattern_destroy p

foreign import ccall "cairo_pattern_create_for_surface" c_cairo_pattern_create_for_surface ::
	Ptr (CairoSurfaceT s ps) -> IO (Ptr (CairoPatternT ps))

cairoPatternGetSurface :: PrimMonad m =>
	CairoPatternSurfaceT (PrimState m) -> m (CairoSurfaceT s (PrimState m))
cairoPatternGetSurface (CairoPatternSurfaceT fpt) =
	unsafeIOToPrim $ CairoSurfaceT <$> withForeignPtr fpt \ppt -> alloca \pps -> do
		cairoStatusToThrowError =<< c_cairo_pattern_get_surface ppt pps
		p <- c_cairo_surface_reference =<< peek pps
		newForeignPtr p $ c_cairo_surface_destroy p

foreign import ccall "cairo_pattern_get_surface" c_cairo_pattern_get_surface ::
	Ptr (CairoPatternT ps) -> Ptr (Ptr (CairoSurfaceT s ps)) -> IO #{type cairo_status_t}

foreign import ccall "cairo_surface_reference" c_cairo_surface_reference ::
	Ptr (CairoSurfaceT s ps) -> IO (Ptr (CairoSurfaceT s ps))

raiseIfErrorPattern :: CairoPatternT s -> IO ()
raiseIfErrorPattern (CairoPatternT fpt) = withForeignPtr fpt \pt ->
	cairoStatusToThrowError =<< c_cairo_pattern_status pt

foreign import ccall "cairo_pattern_status" c_cairo_pattern_status ::
	Ptr (CairoPatternT s) -> IO #{type cairo_status_t}