packages feed

nanovg-0.1.0.0: src/NanoVG.hs

module NanoVG
  (module NanoVG.Internal
  ,textBreakLines
  ,textGlyphPositions
  ,text
  ) where

import qualified Data.Vector as V
import           Control.Monad
import qualified Data.Text as T
import           Data.Text.Foreign
import           Foreign.C.Types
import           Foreign.Marshal.Alloc
import           Foreign.Ptr
import           Foreign.Storable
import qualified NanoVG.Internal as Internal
import           NanoVG.Internal hiding (textBreakLines,textGlyphPositions,text)

-- | High level wrapper around NanoVG.Internal.textBreakLines
-- This uses the fonts for width calculations so make sure you have them setup properly
textBreakLines :: Context -> T.Text -> CFloat -> CInt -> (TextRow -> CInt -> IO ()) -> IO ()
textBreakLines c text' width' chunkSize f =
  withCStringLen text' $
  \(startPtr,len) ->
    allocaBytesAligned (sizeOf (undefined :: TextRow) * fromIntegral chunkSize)
                       (alignment (undefined :: TextRow)) $
    \arrayPtr ->
      do let endPtr = startPtr `plusPtr` len
             loop line ptr =
               do count <-
                    Internal.textBreakLines c ptr endPtr width' arrayPtr chunkSize
                  when (count > 0) $
                    loop (line + count) =<< readChunk line arrayPtr count
         loop 0 startPtr
  where readChunk
          :: CInt -> TextRowPtr -> CInt -> IO (Ptr CChar)
        readChunk baseline arrayPtr count =
          do forM_ [0 .. (count - 1)] $
               \i ->
                 do textRow <-
                      peekElemOff arrayPtr
                                  (fromIntegral i)
                    f textRow (baseline + i)
             next <$>
               peekElemOff arrayPtr
                           (fromIntegral (count - 1))

-- | High level wrapper around NanoVG.Internal.textGlyphPositions
-- Might be changed to return a vector in the future
textGlyphPositions :: Context -> CFloat -> CFloat -> Ptr CChar -> Ptr CChar -> CInt -> IO (V.Vector GlyphPosition)
textGlyphPositions c x y startPtr endPtr maxGlyphs =
  allocaBytesAligned
    (sizeOf (undefined :: GlyphPosition) * fromIntegral maxGlyphs)
    (alignment (undefined :: GlyphPosition)) $
  \arrayPtr ->
    do count <-
         Internal.textGlyphPositions c x y startPtr endPtr arrayPtr maxGlyphs
       readChunk arrayPtr count
  where readChunk
          :: GlyphPositionPtr -> CInt -> IO (V.Vector GlyphPosition)
        readChunk arrayPtr count =
          V.generateM (fromIntegral count) $
          \i ->
            peekElemOff arrayPtr
                        (fromIntegral i)

text :: Context -> CFloat -> CFloat -> T.Text -> IO ()
text c x y t = withCStringLen t $ \(ptr,len) -> Internal.text c x y ptr (ptr `plusPtr` len)