| Safe Haskell | None |
|---|---|
| Language | GHC2024 |
NanoUI.Testing
Description
Deterministic frame execution and render inspection for tests and tools.
Application code should use a backend's runner, such as
runSdlApp in NanoUI.Backend.Sdl, instead of this module.
Synopsis
- runFrame :: Context -> Input -> NanoUI a -> IO (a, [FrameMsg], DrawData, Bool)
- runFrameEff :: forall (es :: [Effect]) a. IOE :> es => (forall x. Eff es x -> IO x) -> Context -> Input -> Eff (Ui ': es) a -> IO (a, [FrameMsg], DrawData, Bool)
- runFrameReduce :: (Typeable msg, Eq model) => (msg -> model -> model) -> Context -> Input -> model -> (model -> NanoUI a) -> IO (a, model, [msg], DrawData, Bool)
- runFrameReduceEff :: forall (es :: [Effect]) msg model a. (IOE :> es, Typeable msg, Eq model) => (forall x. Eff es x -> IO x) -> (msg -> model -> model) -> Context -> Input -> model -> (model -> Eff (Ui ': es) a) -> IO (a, model, [msg], DrawData, Bool)
- needsRedraw :: Context -> Input -> Input -> IO Bool
- pointerDragActive :: Context -> IO Bool
- textFieldActive :: Context -> IO Bool
- floatingPanelActive :: Context -> IO Bool
- floatingPanelRects :: Context -> IO (IntMap Rect)
- debugPanelOpen :: Context -> IO Bool
- widgetNodeCount :: Context -> IO Int
- pointerCursorWanted :: Context -> Input -> IO Bool
- cursorKindIs :: Context -> Input -> UiCursorKind -> IO Bool
- uiCursorKind :: Context -> Input -> IO UiCursorKind
- data UiCursorKind
- computePopupPosition :: Float -> Float -> Float -> Float -> Float -> PopupAnchor -> PopupPlacement -> Float -> (Float, Float)
- scrollBarLayout :: ScrollBarSlot -> DirTag -> Float -> Float -> Float -> Float -> Padding -> Float -> Float -> Maybe ScrollBarLayout
- data ScrollBarLayout = ScrollBarLayout {}
- sliderTrackBounds :: Float -> Float -> Float -> Float -> Rect
- colorPickerSvSquare :: Rect -> Rect
- widgetStoreBaseColor :: WidgetStore -> WidgetId -> Color -> Color
- widgetStoreColor :: WidgetStore -> WidgetId -> Color -> Color
- collectTextSpans :: Context -> IO [(Rect, Text, Color, Color, Rect)]
- collectRasterSpans :: Context -> Input -> IO ([(Rect, Text, Color, Color, Rect)], [(Rect, Text, Color, Color, Rect)])
- collectOverlayTextSpans :: Context -> Input -> IO [(Rect, Text, Color, Color, Rect)]
- ctxSpanBase :: Context -> SpanArena
- ctxSpanOverlay :: Context -> SpanArena
- data SpanArena
- spanArenaCount :: SpanArena -> IO Int
- foldSpanArena :: SpanArena -> (Rect -> Text -> Color -> Color -> Rect -> IO ()) -> IO ()
- data Context
- newContext :: IO Context
- newPixelContext :: IO Context
- ctxTheme :: Context -> IORef Theme
- ctxPaintFull :: Context -> IORef Bool
- ctxFontMetrics :: Context -> FontMetrics
- setHost :: Typeable a => Context -> a -> IO ()
- askHost :: forall a (es :: [Effect]). (Typeable a, Ui :> es) => Eff es (Maybe a)
- withFontMetrics :: Context -> FontMetrics -> Context
- withMonoFontMetrics :: Context -> FontMetrics -> Context
- withMeasureText :: Context -> (Text -> IO (Float, Float)) -> Context
- withFontResolver :: Context -> (Float -> FontWeight -> FontStyle -> FontVariant -> IO (FontMetrics, Bool)) -> (Float -> FontWeight -> FontStyle -> FontVariant -> Text -> IO (Float, Float)) -> Context
- wrapMeasureCache :: Float -> Context -> (Text -> IO (Float, Float)) -> Context
- withExternalText :: Context -> Bool -> Context
- enableMeasureCache :: Context -> IO Context
- withTheme :: Context -> Theme -> IO Context
- setTheme :: Context -> Theme -> IO ()
- getTheme :: Context -> IO Theme
- markDirty :: Context -> IO ()
- clearDirty :: Context -> IO ()
- clearMeasureCache :: Context -> IO ()
- isDirty :: Context -> IO Bool
- setWakeLoop :: Context -> IO () -> IO ()
- data DamageRequest
- = ReqWidget !WidgetId !DamageBounds
- | ReqKey !Int !DamageBounds
- | ReqRect !Rect
- | ReqPeers ![WidgetId] !DamageBounds
- | ReqFull
- requestDamage :: Context -> DamageRequest -> IO ()
- damageWidget :: Context -> WidgetId -> DamageBounds -> IO ()
- damageKey :: Context -> Int -> DamageBounds -> IO ()
- damageRect :: Context -> Rect -> IO ()
- damagePeers :: Context -> [WidgetId] -> DamageBounds -> IO ()
- damageFull :: Context -> IO ()
- getHotId :: Context -> IO WidgetId
- getFocusId :: Context -> IO WidgetId
- getPrevRect :: Context -> WidgetId -> IO (Maybe Rect)
- getPrevClipRect :: Context -> WidgetId -> IO (Maybe Rect)
- getStore :: Context -> IO WidgetStore
- getScrollOffset :: Context -> WidgetId -> IO Float
- setScrollOffset :: Context -> WidgetId -> Float -> IO ()
- textInputEditActive :: Context -> IO Bool
- modalActive :: Context -> IO Bool
- overlayConsumesQuit :: Context -> Input -> IO Bool
- withClipboard :: Context -> IO (Maybe Text) -> (Text -> IO Bool) -> Context
- getAnimationValue :: Context -> WidgetId -> IO Float
- setAnimationValue :: Context -> WidgetId -> Float -> IO ()
- startAnimation :: Context -> WidgetId -> Float -> Float -> Float -> IO ()
- startAnimationEase :: Context -> WidgetId -> Float -> Float -> Float -> Ease -> IO ()
- startAnimationEaseDelay :: Context -> WidgetId -> Float -> Float -> Float -> Ease -> Float -> IO ()
- startSpring :: Context -> WidgetId -> SpringParams -> Float -> IO ()
- anyAnimating :: Context -> IO Bool
- registerImage :: Context -> ImageId -> Int -> Int -> ByteString -> IO Bool
- registerImages :: Foldable f => Context -> f (ImageId, Int, Int, ByteString) -> IO Bool
- atlasTextureId :: Int
- atlasSnapshot :: Context -> IO (Maybe (Int, Int, ForeignPtr Word8, Int))
- data FrameMsg where
- decodeMessages :: (Foldable f, Typeable a) => f FrameMsg -> [a]
- reduceMessages :: (Foldable f, Typeable msg) => (msg -> model -> model) -> model -> f FrameMsg -> model
- reduceUpdates :: (Foldable f, Typeable model) => model -> f FrameMsg -> model
- data DrawData = DrawData {}
- data DrawCmd = DrawCmd {}
- data DrawOp
- = FillRect !Rect !Color
- | FillRoundedRect !Rect !Float !Color
- | FillTriangle !Float !Float !Float !Float !Float !Float !Color
- | FillCircle !Float !Float !Float !Color
- | Stroke !Float !Float !Float !Float !Float !Color
- | StrokeRoundedRect !Rect !Float !Float !Color
- | StrokeCircle !Float !Float !Float !Float !Color
- | StrokeLineAA !Float !Float !Float !Float !Float !Color
- | FillQuadGradient !Rect !Color !Color !Color !Color
- | DrawImageRect !Rect !Int !Float !Float !Float !Float !Color
- | DrawText !Float !Float !Float !Float !Text !Color
- | DrawTextStyled !Float !Float !TextFont !Text !Color
- drawTextBox :: FontMetrics -> Float -> Float -> Float -> Float -> Text -> Rect
- data Layer
- data LayerSlice = LayerSlice {
- sliceOffset :: !Int
- sliceCount :: !Int
- drawCmdNull :: DrawData -> Bool
- drawCmdElems :: DrawData -> [DrawCmd]
- forDrawCmdsInLayer_ :: Layer -> DrawData -> (DrawCmd -> IO ()) -> IO ()
- drawCmdCount :: DrawData -> Int
- vertexSize :: Int
- indexSize :: Int
- backdropDimTextureId :: Int
- glyphAtlasTextureId :: Int
- data Damage
- takeDamage :: Context -> IO Damage
- damageIsEmpty :: Damage -> Bool
- data Eff (es :: [Effect]) a
- runEff :: HasCallStack => Eff '[IOE] a -> IO a
- data IOE (a :: Type -> Type) b
- class (e :: Effect) :> (es :: [Effect])
- askContext :: forall (es :: [Effect]). Ui :> es => Eff es Context
- askInput :: forall (es :: [Effect]). Ui :> es => Eff es Input
- data Ui (a :: Type -> Type) b
- uiIO :: forall (es :: [Effect]) a. Ui :> es => IO a -> Eff es a
- data Compact a
- compactHost :: Typeable a => Context -> a -> IO (Compact a)
- askCompact :: forall a (es :: [Effect]). (Typeable a, Ui :> es) => Eff es (Maybe a)
- lineWidth :: FontMetrics -> Text -> Float
- textIndexAtX :: FontMetrics -> Text -> Float -> Int
- caretX :: FontMetrics -> Text -> Int -> Float
- selectionSpans :: FontMetrics -> Text -> Int -> Int -> [(Float, Float)]
- textNodeFontWeight :: Int -> FontWeight
- textNodeFontStyle :: Int -> FontStyle
- textNodeTextDecoration :: Int -> TextDecoration
Frame
runFrameEff :: forall (es :: [Effect]) a. IOE :> es => (forall x. Eff es x -> IO x) -> Context -> Input -> Eff (Ui ': es) a -> IO (a, [FrameMsg], DrawData, Bool) Source #
runFrameReduce :: (Typeable msg, Eq model) => (msg -> model -> model) -> Context -> Input -> model -> (model -> NanoUI a) -> IO (a, model, [msg], DrawData, Bool) Source #
runFrameReduceEff :: forall (es :: [Effect]) msg model a. (IOE :> es, Typeable msg, Eq model) => (forall x. Eff es x -> IO x) -> (msg -> model -> model) -> Context -> Input -> model -> (model -> Eff (Ui ': es) a) -> IO (a, model, [msg], DrawData, Bool) Source #
cursorKindIs :: Context -> Input -> UiCursorKind -> IO Bool Source #
uiCursorKind :: Context -> Input -> IO UiCursorKind Source #
data UiCursorKind Source #
Constructors
| UiCursorDefault | |
| UiCursorPointer | |
| UiCursorText | |
| UiCursorGrab | |
| UiCursorGrabbing | |
| UiCursorNsResize | |
| UiCursorEwResize | |
| UiCursorNwseResize | |
| UiCursorNeswResize |
Instances
| Eq UiCursorKind Source # | |
Defined in NanoUI.Input | |
| Show UiCursorKind Source # | |
Defined in NanoUI.Input Methods showsPrec :: Int -> UiCursorKind -> ShowS # show :: UiCursorKind -> String # showList :: [UiCursorKind] -> ShowS # | |
computePopupPosition :: Float -> Float -> Float -> Float -> Float -> PopupAnchor -> PopupPlacement -> Float -> (Float, Float) Source #
scrollBarLayout :: ScrollBarSlot -> DirTag -> Float -> Float -> Float -> Float -> Padding -> Float -> Float -> Maybe ScrollBarLayout Source #
data ScrollBarLayout Source #
Instances
| Eq ScrollBarLayout Source # | |
Defined in NanoUI.Frame.Scroll.Geometry Methods (==) :: ScrollBarLayout -> ScrollBarLayout -> Bool # (/=) :: ScrollBarLayout -> ScrollBarLayout -> Bool # | |
| Show ScrollBarLayout Source # | |
Defined in NanoUI.Frame.Scroll.Geometry Methods showsPrec :: Int -> ScrollBarLayout -> ShowS # show :: ScrollBarLayout -> String # showList :: [ScrollBarLayout] -> ShowS # | |
colorPickerSvSquare :: Rect -> Rect Source #
The square the saturation / value field fills, centered in its node.
widgetStoreBaseColor :: WidgetStore -> WidgetId -> Color -> Color Source #
widgetStoreColor :: WidgetStore -> WidgetId -> Color -> Color Source #
collectRasterSpans :: Context -> Input -> IO ([(Rect, Text, Color, Color, Rect)], [(Rect, Text, Color, Color, Rect)]) Source #
ctxSpanBase :: Context -> SpanArena Source #
ctxSpanOverlay :: Context -> SpanArena Source #
Context
newContext :: IO Context Source #
newPixelContext :: IO Context Source #
A headless context for tests: 16px monospace metrics, the measure cache on, text kept out of the vertex buffer, and the default theme.
ctxFontMetrics :: Context -> FontMetrics Source #
withFontMetrics :: Context -> FontMetrics -> Context Source #
withMonoFontMetrics :: Context -> FontMetrics -> Context Source #
withFontResolver :: Context -> (Float -> FontWeight -> FontStyle -> FontVariant -> IO (FontMetrics, Bool)) -> (Float -> FontWeight -> FontStyle -> FontVariant -> Text -> IO (Float, Float)) -> Context Source #
withTheme :: Context -> Theme -> IO Context Source #
Configure a context's theme. Goes through setTheme so a theme swapped
between frames invalidates the caches keyed on it, drawing-op caches
included, instead of leaving widgets painting the previous theme.
clearDirty :: Context -> IO () Source #
clearMeasureCache :: Context -> IO () Source #
data DamageRequest Source #
Explicit damage invalidation request queued during frame evaluation.
Constructors
| ReqWidget !WidgetId !DamageBounds | Invalidate widget layout bounds (old & new) |
| ReqKey !Int !DamageBounds | Invalidate widget bounds by integer key |
| ReqRect !Rect | Invalidate an explicit window-space rectangle |
| ReqPeers ![WidgetId] !DamageBounds | Invalidate a collection of widgets |
| ReqFull | Force full window invalidation |
Instances
| Eq DamageRequest Source # | |
Defined in NanoUI.Context.Types Methods (==) :: DamageRequest -> DamageRequest -> Bool # (/=) :: DamageRequest -> DamageRequest -> Bool # | |
| Show DamageRequest Source # | |
Defined in NanoUI.Context.Types Methods showsPrec :: Int -> DamageRequest -> ShowS # show :: DamageRequest -> String # showList :: [DamageRequest] -> ShowS # | |
requestDamage :: Context -> DamageRequest -> IO () Source #
damageWidget :: Context -> WidgetId -> DamageBounds -> IO () Source #
damagePeers :: Context -> [WidgetId] -> DamageBounds -> IO () Source #
damageFull :: Context -> IO () Source #
setScrollOffset :: Context -> WidgetId -> Float -> IO () Source #
Move a scroller to an offset along its main axis. Cancels a glide in flight: whoever sets an offset outright owns it.
startAnimationEaseDelay :: Context -> WidgetId -> Float -> Float -> Float -> Ease -> Float -> IO () Source #
startSpring :: Context -> WidgetId -> SpringParams -> Float -> IO () Source #
anyAnimating :: Context -> IO Bool Source #
Whether the frame loop has to keep drawing: an animation is running, or a scroller is still gliding onto its target.
Images
registerImage :: Context -> ImageId -> Int -> Int -> ByteString -> IO Bool Source #
atlasTextureId :: Int Source #
GPU texture id shared by every packed image so draw cmds batch.
Messages
reduceMessages :: (Foldable f, Typeable msg) => (msg -> model -> model) -> model -> f FrameMsg -> model Source #
Draw
Constructors
| DrawData | |
Fields
| |
Constructors
| DrawCmd | |
Instances
| Eq DrawCmd Source # | |
| Show DrawCmd Source # | |
| Prim DrawCmd Source # | |
Defined in NanoUI.Draw.Types Methods sizeOfType# :: Proxy DrawCmd -> Int# # alignmentOfType# :: Proxy DrawCmd -> Int# # alignment# :: DrawCmd -> Int# # indexByteArray# :: ByteArray# -> Int# -> DrawCmd # readByteArray# :: MutableByteArray# s -> Int# -> State# s -> (# State# s, DrawCmd #) # writeByteArray# :: MutableByteArray# s -> Int# -> DrawCmd -> State# s -> State# s # setByteArray# :: MutableByteArray# s -> Int# -> Int# -> DrawCmd -> State# s -> State# s # indexOffAddr# :: Addr# -> Int# -> DrawCmd # readOffAddr# :: Addr# -> Int# -> State# s -> (# State# s, DrawCmd #) # writeOffAddr# :: Addr# -> Int# -> DrawCmd -> State# s -> State# s # setOffAddr# :: Addr# -> Int# -> Int# -> DrawCmd -> State# s -> State# s # | |
Constructors
| FillRect !Rect !Color | |
| FillRoundedRect !Rect !Float !Color | |
| FillTriangle !Float !Float !Float !Float !Float !Float !Color | |
| FillCircle !Float !Float !Float !Color | |
| Stroke !Float !Float !Float !Float !Float !Color | |
| StrokeRoundedRect !Rect !Float !Float !Color | |
| StrokeCircle !Float !Float !Float !Float !Color | |
| StrokeLineAA !Float !Float !Float !Float !Float !Color | |
| FillQuadGradient !Rect !Color !Color !Color !Color | |
| DrawImageRect !Rect !Int !Float !Float !Float !Float !Color | |
| DrawText !Float !Float !Float !Float !Text !Color | Pen at (x, y) is the alignment point. ax 0..1 is left..right. ay 0..1 is
bottom..top. ay < 0 means baseline (x is left, y is the baseline). Glyph size
is the host font ( |
| DrawTextStyled !Float !Float !TextFont !Text !Color | Text in a font of its own, its line box's top left corner at (x, y). |
drawTextBox :: FontMetrics -> Float -> Float -> Float -> Float -> Text -> Rect Source #
Pixel box for a DrawText using host advances. diagrams text has no
envelope, so plot sizing uses this instead of fontSizeL.
Constructors
| LayerBackground | |
| LayerContent | |
| LayerOverlay | |
| LayerChrome |
data LayerSlice Source #
Constructors
| LayerSlice | |
Fields
| |
Instances
drawCmdNull :: DrawData -> Bool Source #
drawCmdElems :: DrawData -> [DrawCmd] Source #
drawCmdCount :: DrawData -> Int Source #
vertexSize :: Int Source #
Constructors
| DamageFull | |
| DamageClip Rect |
damageIsEmpty :: Damage -> Bool Source #
Effectful
The Eff monad provides the implementation of a computation that performs
an arbitrary set of effects. In , Eff es aes is a type-level list that
contains all the effects that the computation may perform. For example, a
computation that produces an Integer by consuming a String from the
global environment and acting upon a single mutable value of type Bool
would have the following type:
(ReaderString:>es,StateBool:>es) =>EffesInteger
Abstracting over the list of effects with (:>):
- Allows the computation to be used in functions that may perform other effects.
- Allows the effects to be handled in any order.
Instances
| IOE :> es => MonadBaseControl IO (Eff es) # | Instance included for compatibility with existing code. Usage of Note: the unlifting strategy for |
| (Show e, Error e :> es, MonadError e (Eff es)) => MonadError e (Eff es) # | Instance included for compatibility with existing code. |
Defined in Effectful.Internal.MTL | |
| (Reader r :> es, MonadReader r (Eff es)) => MonadReader r (Eff es) # | Instance included for compatibility with existing code. |
| (State s :> es, MonadState s (Eff es)) => MonadState s (Eff es) # | Instance included for compatibility with existing code. |
| (Monoid w, Writer w :> es, MonadWriter w (Eff es)) => MonadWriter w (Eff es) # | Instance included for compatibility with existing code. |
| IOE :> es => MonadBase IO (Eff es) # | Instance included for compatibility with existing code. Usage of |
Defined in Effectful.Internal.Monad | |
| MonadCatch (Eff es) # | |
Defined in Effectful.Internal.Monad Methods catch :: (HasCallStack, Exception e) => Eff es a -> (e -> Eff es a) -> Eff es a # catchNoPropagate :: Exception e => Eff es a -> (ExceptionWithContext e -> Eff es a) -> Eff es a # | |
| MonadMask (Eff es) # | |
Defined in Effectful.Internal.Monad Methods mask :: HasCallStack => ((forall a. Eff es a -> Eff es a) -> Eff es b) -> Eff es b # uninterruptibleMask :: HasCallStack => ((forall a. Eff es a -> Eff es a) -> Eff es b) -> Eff es b # generalBracket :: HasCallStack => Eff es a -> (a -> ExitCase b -> Eff es c) -> (a -> Eff es b) -> Eff es (b, c) # | |
| MonadThrow (Eff es) # | |
Defined in Effectful.Internal.Monad Methods throwM :: (HasCallStack, Exception e) => e -> Eff es a # rethrowM :: Exception e => ExceptionWithContext e -> Eff es a # | |
| NonDet :> es => Alternative (Eff es) # | Since: effectful-core-2.2.0.0 |
| Applicative (Eff es) # | |
| Functor (Eff es) # | |
| Monad (Eff es) # | |
| NonDet :> es => MonadPlus (Eff es) # | Since: effectful-core-2.2.0.0 |
| Fail :> es => MonadFail (Eff es) # | |
Defined in Effectful.Internal.Monad Methods fail :: HasCallStack => String -> Eff es a # | |
| MonadFix (Eff es) # | |
Defined in Effectful.Internal.Monad | |
| IOE :> es => MonadIO (Eff es) # | |
Defined in Effectful.Internal.Monad | |
| Prim :> es => PrimMonad (Eff es) # | |
| IOE :> es => MonadUnliftIO (Eff es) # | Instance included for compatibility with existing code. Usage of Note: the unlifting strategy for |
Defined in Effectful.Internal.Monad | |
| Monoid a => Monoid (Eff es a) # | |
| Semigroup a => Semigroup (Eff es a) # | |
| type PrimState (Eff es) # | |
Defined in Effectful.Internal.Monad | |
| type StM (Eff es) a # | |
Defined in Effectful.Internal.Monad | |
runEff :: HasCallStack => Eff '[IOE] a -> IO a #
Run an Eff computation with side effects.
For running pure computations see runPureEff.
data IOE (a :: Type -> Type) b #
Run arbitrary IO computations via MonadIO or MonadUnliftIO.
Note: it is not recommended to use this effect in application code as it is too liberal. Ideally, this is only used in handlers of more fine-grained effects.
Instances
| type DispatchOf IOE # | |
Defined in Effectful.Internal.Monad | |
| newtype StaticRep IOE # | |
Defined in Effectful.Internal.Monad | |
class (e :: Effect) :> (es :: [Effect]) #
A constraint that requires that a particular effect e is a member of the
type-level list es. This is used to parameterize an Eff
computation over an arbitrary list of effects, so long as e is somewhere
in the list.
For example, a computation that only needs access to a mutable value of type
Integer would have the following type:
StateInteger:>es =>Effes ()
Instances
| (TypeError (('Text "There is no handler for '" ':<>: 'ShowType e) ':<>: 'Text "' in the context") :: Constraint) => e :> ('[] :: [Effect]) # | |
Defined in Effectful.Internal.Effect Methods reifyIndex :: Int # | |
| e :> (e ': es) # | |
Defined in Effectful.Internal.Effect Methods reifyIndex :: Int # | |
| e :> es => e :> (x ': es) # | |
Defined in Effectful.Internal.Effect Methods reifyIndex :: Int # | |
data Ui (a :: Type -> Type) b Source #
Instances
| type DispatchOf Ui Source # | |
Defined in NanoUI.Monad | |
| data StaticRep Ui Source # | |
Compact
A Compact contains fully evaluated, pure, immutable data.
Compact serves two purposes:
- Data stored in a
Compacthas no garbage collection overhead. The garbage collector considers the wholeCompactto be alive if there is a reference to any object within it. - A
Compactcan be serialized, stored, and deserialized again. The serialized data can only be deserialized by the exact binary that created it, but it can be stored indefinitely before deserialization.
Compacts are self-contained, so compacting data involves copying
it; if you have data that lives in two Compacts, each will have a
separate copy of the data.
The cost of compaction is fully evaluating the data + copying it. However,
because compact does not stop-the-world, retaining internal sharing during
the compaction process is very costly. The user can choose whether to
compact or compactWithSharing.
When you have a , you can get a pointer to the actual object
in the region using Compact agetCompact. The Compact type
serves as handle on the region itself; you can use this handle
to add data to a specific Compact with compactAdd or
compactAddWithSharing (giving you a new handle which corresponds
to the same compact region, but points to the newly added object
in the region). At the moment, due to technical reasons,
it's not possible to get the if you only have an Compact aa,
so make sure you hold on to the handle as necessary.
Data in a compact doesn't ever move, so compacting data is also a way to pin arbitrary data structures in memory.
There are some limitations on what can be compacted:
- Functions. Compaction only applies to data.
- Pinned
ByteArray#objects cannot be compacted. This is for a good reason: the memory is pinned so that it can be referenced by address (the address might be stored in a C data structure, for example), so we can't make a copy of it to store in theCompact. - Objects with mutable pointer fields (e.g.
IORef,MutableArray) also cannot be compacted, because subsequent mutation would destroy the property that a compact is self-contained.
If compaction encounters any of the above, a CompactionFailed
exception will be thrown by the compaction operation.
Text measurement
textIndexAtX :: FontMetrics -> Text -> Float -> Int Source #
The character index whose caret is nearest x: from the shaped carets
when the text was prepared by a shaping host, which handles clusters and
right-to-left runs, and otherwise from the same advances and kerning as
pushText, so the caret lands where the glyph to its left was
drawn.
caretX :: FontMetrics -> Text -> Int -> Float Source #
Where the caret before character i of txt sits: a shaped caret when
the snapshot was prepared for txt, else the width of the characters
before it.
selectionSpans :: FontMetrics -> Text -> Int -> Int -> [(Float, Float)] Source #
The horizontal extents covering characters lo to hi: one span for
left-to-right text, and a span per direction run where a selection crosses
right-to-left text.
textNodeFontWeight :: Int -> FontWeight Source #
textNodeFontStyle :: Int -> FontStyle Source #