packages feed

nano-ui-0.1.0.0: test/integration/Cases/RichText.hs

module Cases.RichText
  ( runRichTextWrapTest
  , runRichTextLinkTest
  ) where

import Control.Monad (void)
import Data.IORef (IORef)
import Data.Text qualified as T
import NanoUI
import NanoUI.Context (Context (..))
import NanoUI.Testing (UiCursorKind (..), cursorKindIs, runFrame)
import NanoUI.Testing.Assert (assert, assertEq, withInput)
import NanoUI.Testing.Harness (clickPair, drawQuads, warmup2)

-- | A paragraph wraps at its column's width, taking a line's height per line,
-- and mixed pieces share a line.
runRichTextWrapTest :: Context -> IORef Int -> IO ()
runRichTextWrapTest ctx failed = do
  let inp = withInput 400 400
      paragraph = [inlineText (T.replicate 12 "word "), strong "bold", " end"]
      ui = columnWith (fixedW 200) $ do
        one <- fst <$> richText' ["word"]
        wrapped <- fst <$> richText' paragraph
        pure (one, wrapped)
  (one, wrapped) <- warmup2 ctx inp ui
  let Rect _ _ _ lineH = respRect one
      Rect _ _ w h = respRect wrapped
  assert failed (lineH > 0)
  assert failed (w <= 200)
  -- Twelve words and two more pieces cannot fit on one 200px line.
  assert failed (h >= 2 * lineH)
  assertEq failed 0 (round h `mod` round lineH :: Int)

-- | A link reports its target when clicked and shows the pointer cursor;
-- text beside it reports nothing.
runRichTextLinkTest :: Context -> IORef Int -> IO ()
runRichTextLinkTest ctx failed = do
  let inp0 = withInput 400 400
      ui = column (richText' ["Go to ", hyperlink "docs-target" "the docs", " now"])
      fm = ctxFontMetrics ctx
  (resp, _) <- warmup2 ctx inp0 ui
  prefixW <- sum <$> mapM (lineWidthIO fm) ["Go", " ", "to", " "]
  linkW <- sum <$> mapM (lineWidthIO fm) ["the", " ", "docs"]
  let Rect rx ry _ rh = respRect resp
      onLink = V2 (rx + prefixW + linkW / 2) (ry + rh / 2)
      onText = V2 (rx + 2) (ry + rh / 2)
      clickAt pos = do
        let (press, release) = clickPair inp0 pos
        void (runFrame ctx inp0 {inputMousePos = pos} ui)
        void (runFrame ctx press ui)
        ((_, clicked), _, _, _) <- runFrame ctx release ui
        pure clicked
  linkClick <- clickAt onLink
  assertEq failed (Just "docs-target") linkClick
  pointer <- cursorKindIs ctx inp0 {inputMousePos = onLink} UiCursorPointer
  assert failed pointer
  -- The hovered link is underlined once, across its words and the space
  -- between them.
  (_, _, dd, _) <- runFrame ctx inp0 {inputMousePos = onLink} ui
  quads <- drawQuads dd
  let underlines = [r | (r@(Rect _ _ w h), _) <- quads, h < 3, abs (w - linkW) < 0.5]
  assertEq failed 1 (length underlines)
  textClick <- clickAt onText
  assertEq failed Nothing textClick
  plainCursor <- cursorKindIs ctx inp0 {inputMousePos = onText} UiCursorPointer
  assert failed (not plainCursor)