SVGFonts-1.8.0.1: Fonts from the SVG-Font format
Safe HaskellNone
LanguageHaskell2010

Graphics.SVGFonts.Wrap

Description

The module implements text wrapping. The following example roughly outlines the functionality of the module. In the example, we try to wrap the text at spaces into lines of height 10 and width

  1. between 40 and 50, which is mostly successful, except the first line: because the word "gentlemen" is long. Therefore the word gentlemen is tried to be split at each two chars, so that the width of the first line is between 0 and
  2. Now the splitting is successful.
  3. between 0 and 2, which is unsuccessful (splitting at spaces such that 0 < length_of_the_first_line <= 2 is not possible). Then it tries to split the text at each two chars, which is unsuccessful again (2 is just too little). Then the third splitter is applied, which is const Nothing, therefore the result is Nothing (= unsuccessful split).
example :: (Maybe [String], Maybe [String])
example =
  ( wrapText def 10 splits1 text
  , wrapText def 10 splits2 text
  )
  where
    text = "mornin' gentlemen, how is the business going today?"
    splits1 =
      [ (splitAtSpaces, (40 :: Double, 50))
      , (splitEachTwoChars, (0, 50))
      , (const Nothing, (-1, 1/0))
      ]

    splits2 =
      [ (splitAtSpaces, (0 :: Double, 2))
      , (splitEachTwoChars, (0, 2))
      , (const Nothing, (-1, 1/0))
      ]

The result is

( Just ["mornin' gentle-","men, how is the","business going","today?"]
, Nothing
)
Synopsis

Documentation

wrapTextLine :: forall n m. (TypeableFloat n, Monad m) => TextOpts n -> n -> [(String -> m Split, (n, n))] -> String -> m (String, String) Source #

Split the text to a first line and the rest. Given the invocation wrapTextLine opts font_height [(first_split, first_split_bounds), ...] text, the longest modified first line is taken, which holds the following vague specification:

  • The text is split using the first_split function into a prefix and the rest. The first line is the prefix, possibly concatenated with the first line of the rest. In addition, if the rest is not an empty string, the first line is modified using the first_split's elementary modifications.
  • The first line's width is inside first_split_bounds after applying the modification of the first_split.
  • If such line cannot be found, last split is undone and second_split and second_split_bounds is considered.
  • Edge case: If the text is shorter than the bounds, (text, "") is returned.

For better performance, this should be reimplemented using something other than Strings.

wrapText :: forall n m. (TypeableFloat n, Monad m) => TextOpts n -> n -> [(String -> m Split, (n, n))] -> String -> m [String] Source #

Using wrapTextLine, split the text to a list of lines.

splitAtSpaces :: Monad m => String -> m Split Source #

Quite useful argument for wrapTextLine. Split the text at spaces, remove the spaces at which we split.

splitEachTwoChars :: Monad m => String -> m Split Source #

Quite unuseful example argument for wrapTextLine. Something more sophisticated should be used in real world... something that would split words at syllable boundaries. Split the text at each two characters, interleaving the splits with a hyphen.