nano-ui
Safe HaskellNone
LanguageGHC2024

NanoUI.Context

Description

The Context a view runs against, and the operations on its state: focus, dirty flags and damage, the widget store, drawing and measure caches, overlays, and host hooks. Backends and advanced widgets use this module; views normally only need NanoUI.

Synopsis

Documentation

data Context Source #

Constructors

Context 

Fields

data DrawingEntry Source #

A registered drawing: content version plus the op builder. The version participates in the draw-op cache key, so a builder whose output changes without its size changing must bump the version to invalidate.

Constructors

DrawingEntry 

data DrawFitCache Source #

Constructors

DrawFitCache 

Fields

data SpanCacheEntry Source #

Cached text-span layout for one arena node. Key fields are every input that changes the produced spans; sceSpans is the shared result. The whole cache is dropped on theme or font-scale changes.

data WidgetTextPlacement Source #

A cacheable widget label is a single line (or absent for close buttons). Coordinates are relative to the node origin; paint translates them without rebuilding a list or invalidating the cache when a widget scrolls.

setWakeLoop :: Context -> IO () -> 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

Instances details
Eq DamageRequest Source # 
Instance details

Defined in NanoUI.Context.Types

Show DamageRequest Source # 
Instance details

Defined in NanoUI.Context.Types

cachedDrawingOps :: Context -> WidgetId -> Int -> Rect -> DrawingBuild -> IO (SmallArray DrawOp) Source #

Rebuild draw ops when the content version or width/height change. A move only translates. An unversioned drawing (content 0) additionally drops its cache while the widget is animating, since it has no other invalidation signal; versioned drawings are invalidated by their content key alone.

cachedWidgetLayout :: Context -> WidgetId -> Double -> Double -> Float -> Int -> Layout -> IO Layout -> IO Layout Source #

Reuse a derived layout while envelope, font, content key, and caller layout match.

pruneDrawOpCache :: Context -> IO () Source #

Drop cached ops for drawings that did not rebuild this frame.

type CustomMeasureFn = FontMetrics -> (Float, Float) -> (Float, Float) Source #

Custom node measurement: font metrics and available (width, height) to the node's desired (width, height).

cachedCustomDrawingOps :: Context -> WidgetId -> Int -> Rect -> CustomDrawContext -> CustomDrawBuild -> IO (SmallArray DrawOp) Source #

Draw ops for a custom widget's paint: the ops refreshCustomDrawingOps settled on this frame while every input still matches, translated if the widget only moved, else a fresh build.

refreshCustomDrawingOps :: Context -> WidgetId -> Int -> Rect -> CustomDrawContext -> CustomDrawBuild -> IO Bool Source #

Settle a custom widget's ops for this frame and cache them for paint, returning whether what it draws changed at an unchanged rect.

A widget that declares a content key is taken at its word, as a versioned drawing is: an unchanged key with unchanged size, interaction state and metrics neither rebuilds the ops nor repaints them, animating or not, so a drawing that reads an animated value has to fold it into its key. One that only moved keeps its ops too; paint translates them. Without a key (0) the build can read anything (a sort flag, a fraction), and nothing but building it shows that its output changed, so it is rebuilt and compared.

Whatever forced a rebuild, the ops it produced decide the damage, so a key bumped without a visible change repaints nothing and a rebuild the key never mentioned still repaints. A new, moved or resized widget reports no change: rect damage covers it.

drawingOpsStale :: Context -> WidgetId -> Int -> Rect -> IO Bool Source #

Whether a versioned drawing's cached ops are for another version at the same rect. Paint rebuilds them; the pixels they covered must repaint too, and checking the version costs nothing next to building the ops here.

data CustomDrawingEntry Source #

A registered custom drawing: its content key plus the op builder. A non-zero key is the author's promise that the ops follow it, so a frame whose key is unchanged neither rebuilds nor repaints them. Key 0 means the drawing carries no key and is rebuilt every frame and compared.

modifyStore :: Context -> (WidgetStore -> WidgetStore) -> IO () Source #

Replace the store with f of it, damaging the keys whose values changed and waking the loop when anything did.

isDisabled :: Context -> WidgetId -> IO Bool Source #

Whether wid was declared inside a disabled scope. A widget asks before its node exists, while the scope it is declared in is still the arena's.

beginThemeScopes :: Context -> Bool -> IO () Source #

Start a view pass with no pushed themes. The first pass of a frame keeps last frame's themes to compare against; a rebuild pass keeps comparing against the same ones.

pushThemeScope :: Context -> Bool -> Theme -> Theme -> IO Int Source #

Add a scope drawn with theme, whose nested scopes modify raw and which is disabled or not, and return its theme index. A theme equal to last frame's at the same index keeps last frame's value.

themeScopesChanged :: Context -> IO Bool Source #

Whether this frame's scopes look different from last frame's: a theme changed, scopes were added or dropped, or nodes moved between scopes.

scopeRawTheme :: Context -> Int -> IO Theme Source #

A scope's theme before any disabled scope faded it.

currentTheme :: Context -> IO Theme Source #

The theme of the scope the view is declaring in.

widgetTheme :: Context -> WidgetId -> IO Theme Source #

The theme of wid's node, or of the current scope before it has one.

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.

setScrollOffset2D :: Context -> WidgetId -> V2 -> IO () Source #

Move a scroller to an offset on both axes. Cancels a glide in flight.

setScrollConfig :: Context -> WidgetId -> ScrollConfig -> IO () Source #

defaultScrollConfig :: ScrollConfig Source #

data ScrollTuning Source #

How far one wheel notch scrolls, and how long a scroll takes to settle. One setting for the whole context; a single scroller can take its own step (see setScrollStep).

Constructors

ScrollTuning 

Fields

  • scrollWheelStep :: Float

    Pixels one wheel notch scrolls. The default is three text lines, which is what Windows and most desktops send a notch as.

  • scrollSmoothTime :: Float

    Seconds a scroll takes to cover most of the distance to its target. 0 (the default) lands on it in the same frame.

Instances

Instances details
Eq ScrollTuning Source # 
Instance details

Defined in NanoUI.Context.Types

Show ScrollTuning Source # 
Instance details

Defined in NanoUI.Context.Types

getScrollTuning :: Context -> IO ScrollTuning Source #

Wheel step and glide time for every scroller in this context.

setScrollTuning :: Context -> ScrollTuning -> IO () Source #

Set the wheel step and glide time. Raising scrollWheelStep makes the wheel cover more ground per notch; a nonzero scrollSmoothTime turns every wheel notch and every ScrollSmooth command into a glide.

getScrollStep :: Context -> WidgetId -> IO Float Source #

This scroller's own wheel step, or 0 when it follows the context's.

setScrollStep :: Context -> WidgetId -> Float -> IO () Source #

Give one scroller its own wheel step, in pixels per notch. 0 puts it back on the context's step. A list whose rows are a fixed height reads best at a whole number of rows per notch.

resolveScrollStep :: Context -> WidgetId -> IO Float Source #

Pixels one wheel notch scrolls this scroller.

data ScrollAxes Source #

Which axes a scroller moves on, and how an offset in window axes (x rightwards, y downwards) maps onto its stored offset. A 1D row scroller keeps its offset in the main-axis slot, so its horizontal offset is the one that needs swapping.

Instances

Instances details
Eq ScrollAxes Source # 
Instance details

Defined in NanoUI.Context.Types

Show ScrollAxes Source # 
Instance details

Defined in NanoUI.Context.Types

data ScrollMetrics Source #

What a scroller looked like on the frame it was last laid out on. Offsets and ranges are in window axes: x rightwards, y downwards, whichever way the scroller itself is built.

Constructors

ScrollMetrics 

Fields

Instances

Instances details
Eq ScrollMetrics Source # 
Instance details

Defined in NanoUI.Context.Scroll

Show ScrollMetrics Source # 
Instance details

Defined in NanoUI.Context.Scroll

getScrollMetrics :: Context -> WidgetId -> IO (Maybe ScrollMetrics) Source #

Geometry of the scroller wid, or Nothing before it has been laid out. Reads the last frame's layout, so it is safe to call while building the next one.

cacheScrollMetrics :: Context -> WidgetId -> ScrollAxes -> Rect -> V2 -> IO () Source #

Record what the scroll pass measured, so the commands and the app can read it between frames. Writes nothing when nothing moved, and nothing at all for a second node sharing this one's widget id. A table's frozen pane and its body share theirs, and letting both publish would rewrite the store every frame and hand the commands a viewport that alternates between panes.

beginScrollMetrics :: Context -> IO () Source #

Start a frame's geometry pass: the first scroll node to publish under a widget id wins for that frame.

getScrollOffsetIn :: Context -> WidgetId -> ScrollAxes -> IO V2 Source #

This scroller's offset in window axes.

setScrollOffsetIn :: Context -> WidgetId -> ScrollAxes -> V2 -> IO () Source #

Move a scroller to an offset in window axes, cancelling any glide. A 1D scroller ignores the axis it does not scroll on.

data ScrollBehavior Source #

Whether a scroll lands on its target at once or glides onto it. ScrollSmooth still lands at once when the context's scrollSmoothTime is 0, so one setting turns smooth scrolling on for the whole app.

Instances

Instances details
Eq ScrollBehavior Source # 
Instance details

Defined in NanoUI.Context.Scroll

Show ScrollBehavior Source # 
Instance details

Defined in NanoUI.Context.Scroll

data ScrollAlign Source #

Where a widget ends up in the viewport once it is scrolled into view.

Constructors

ScrollNearest

Move as little as possible: nothing at all when it is already whole.

ScrollStart

Against the leading edge, at the top or left.

ScrollCenter 
ScrollEnd

Against the trailing edge, at the bottom or right.

Instances

Instances details
Eq ScrollAlign Source # 
Instance details

Defined in NanoUI.Context.Scroll

Show ScrollAlign Source # 
Instance details

Defined in NanoUI.Context.Scroll

scrollTo :: Context -> WidgetId -> V2 -> ScrollBehavior -> IO () Source #

Scroll to an absolute offset, clamped to the scroller's range.

scrollBy :: Context -> WidgetId -> V2 -> ScrollBehavior -> IO () Source #

Scroll by a delta in pixels. Deltas accumulate onto a glide already in flight, so repeated calls keep up rather than fighting each other.

scrollPages :: Context -> WidgetId -> V2 -> ScrollBehavior -> IO () Source #

Scroll by whole viewports: V2 0 1 is one page down, V2 0 (-0.5) half a page up.

scrollToStart :: Context -> WidgetId -> ScrollBehavior -> IO () Source #

Scroll back to the top (and left).

scrollToEnd :: Context -> WidgetId -> ScrollBehavior -> IO () Source #

Scroll to the end of the content.

scrollIntoView :: Context -> WidgetId -> WidgetId -> ScrollAlign -> ScrollBehavior -> IO () Source #

Scroll target into the viewport of the scroller wid it is built inside. Both widgets are read from the last frame's layout, so a widget that was not built then, such as a row a virtualized list left out, cannot be found; scroll to its content rectangle with scrollRectIntoView instead.

scrollRectIntoView :: Context -> WidgetId -> Rect -> ScrollAlign -> ScrollBehavior -> IO () Source #

Scroll a rectangle of the content into view. The rectangle is in content coordinates: the origin is where the content starts, which is where the viewport shows it at offset 0.

applyScrollTarget :: Context -> WidgetId -> ScrollAxes -> V2 -> ScrollBehavior -> IO () Source #

Send a scroller to an offset in window axes, gliding if the caller asked for it and the context is tuned for it. The target must already be clamped to the scroller's range.

scrollTargetOffset :: Context -> WidgetId -> V2 -> IO V2 Source #

Where the scroller is headed: the glide's target if one is in flight, and fallback (normally the current offset) if not. Deltas add onto this so that notches arriving mid-glide are not swallowed.

clampScrollOffset :: V2 -> V2 -> V2 Source #

Hold an offset inside 0 and the scroller's range on each axis.

stepScrollGlides :: Context -> Float -> IO () Source #

Advance every glide by dt seconds. Each one covers the same fraction of what is left every second, so a long throw starts fast and eases in, and at least a pixel a frame so a glide cannot stall on the pixel grid the offsets snap to.

atlasTextureId :: Int Source #

GPU texture id shared by every packed image so draw cmds batch.

ensureMetricCaches :: Context -> IO () Source #

Called once before building a frame. Context configuration remains pure; cache invalidation happens at the IO boundary, including when alternating between differently configured Contexts that share their backing stores.

hasCustomLayoutInputs :: Context -> IO Bool Source #

True when any node has a custom measure function, whose output is not captured by the arena descriptor comparison, so whole-layout reuse must be disabled for the frame.

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.

setHost :: Typeable a => Context -> a -> IO () Source #

setDrawSnapScale :: Context -> Float -> IO () Source #

Set the device pixel scale used to snap geometry origins/endpoints to whole pixels. The SDL backend calls this when the window pixel density is synced.

setDrawSquareGeometry :: Context -> Bool -> IO () Source #

Emit rounded shapes and AA strokes as flat, axis-aligned fills. Software framebuffer hosts enable this so every primitive is a solid quad.

setDrawExternalText :: Context -> Bool -> IO () Source #

Skip text quads in the draw buffer. Hosts that rasterize text from the collected text spans enable this.

getFocusVisible :: Context -> IO Bool Source #

Whether the focused widget shows its focus ring: focus moved by keyboard since the last pointer press.

registerFocusable :: Context -> WidgetId -> IO () Source #

Add wid to this frame's keyboard focus order, unless it is declared in a disabled scope.

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.

data FrameMsg where Source #

Constructors

FrameMsg :: forall a. Typeable a => a -> FrameMsg 

reduceMessages :: (Foldable f, Typeable msg) => (msg -> model -> model) -> model -> f FrameMsg -> model Source #

reduceUpdates :: (Foldable f, Typeable model) => model -> f FrameMsg -> model Source #

data WidgetStore Source #

Widget state for every widget, in maps by value type. Same-type fields that share a widget key use slotKey.

Instances

Instances details
Eq WidgetStore Source # 
Instance details

Defined in NanoUI.Store

Show WidgetStore Source # 
Instance details

Defined in NanoUI.Store

data Slot Source #

Every built-in slot.

Constructors

SlotCursor 
SlotAnchor 
SlotDrag 
SlotDragW 
SlotDrop 
SlotDropPos 
SlotWinSize 
SlotMenuOpen 
SlotMenuPos 
SlotScrollCfg 
SlotScrollOff 
SlotScrollCross 
SlotScrollLinkX 
SlotScrollLinkY 
SlotScrollStep 
SlotScrollAxes 
SlotScrollViewPos 
SlotScrollViewSize 
SlotScrollRange 
SlotScrollContent 
SlotTextAreaRow 
SlotTextAreaCol 
SlotTextAreaPrefCol 
SlotTextAreaScroll 
SlotTextAreaViewport 
SlotTextAreaAnchorRow 
SlotTextAreaAnchorCol 
SlotTextAreaContentW

Cached text-area content extent (max line width, line count * line height) and the node font size they were measured at. Recomputing the width scans every character of the document, so it is cached and only refreshed when the text or font changes.

SlotTextAreaContentH 
SlotTextAreaContentFont 
SlotTextAreaBuffer

Cached TextBuffer for the text area, keyed by its flat Text. Loads and paint reuse it so the document is not re-split into lines every call.

SlotTextAreaChanged

Set (value 1) to signal that the text area's text changed through a path that does not flow through Input (e.g. a context-menu cut/paste). The text area widget reads and clears this on its next frame, so the caller still gets a respChanged pulse for edits that carry no keys or chars.

SlotTextHistory

A text field's undo history with the text it was recorded against, in storeDyn.

SlotTextMode

Which kind of text field a widget id is: 1 single-line, 2 multi-line. Commands sent to the id between frames read it.

SlotTextAreaWidths

A text area's measured line widths, in storeDyn, kept in step with its lines so an edit remeasures only the lines it changed.

SlotTextInputScroll 
SlotSearchCommitted

Search-field debounce bookkeeping. Text slots on the text widget id: the last committed query and the monotonic timestamp of the last edit.

SlotSearchAge 
SlotComboHighlight

Combo box suggestion state (storeInt/storeFloat, keyed by the field widget): the highlighted option index (absolute into the filtered list), the start of the visible window slice (keyboard wheel scrollbar scrolling), and the scrollbar bookkeeping the overlay painter and the widget's thumb-drag gesture share (total filtered count, widest row, x offset, drag axis + grab offset).

SlotComboScroll 
SlotComboCount 
SlotComboScrollX 
SlotComboContentW 
SlotComboDrag 
SlotComboDragOff 
SlotComboCommitted

The last committed value (storeText): typing edits the live field text but only Enter, a row click, or losing focus commits it (Escape reverts).

SlotComboFocus

Had-focus flag (storeInt) so the widget can see the focus-lost transition on the frame after blur and commit then.

SlotComboLive

The field text as the widget last produced it (storeText): a frame-start value that differs from it changed externally (a frame-side row pick or a clipboard menu action), not by typing.

SlotPaneGest

PaneGrid gesture slot (storeInt): 0 none, positive = dragged pane id, negative = split id being resized. Mirrors SlotDrag's press-held-release lifecycle but keyed by the grid widget instead of a per-pane leaf.

SlotPaneGrab

PaneGrid drag grab offset (storePoint): (mouse - pane origin) at grab start.

SlotPaneFocus

PaneGrid keyboard-navigation focus: focused pane id (0 = none, auto-first).

SlotPaneMax

PaneGrid maximize state: maximized pane id (0 = none).

SlotPaneResize

PaneGrid resize start (storePoint): (ratio, main-axis mouse) captured when a divider is first grabbed, so dragging moves it by delta rather than snapping.

SlotPaneNext

PaneGrid id seed (storeInt): next split / pane id to allocate. Strictly monotonic per grid: ids are never reused, so per-pane state keyed by pane id cannot collide with a closed pane's state.

SlotSeen

The value a controlled widget last returned to its caller.

SlotColorBase

A colour picker's opening colour.

SlotNumericHeld

The stepper arrow a numeric field's press holds: 1 up, -1 down.

SlotNumericRepeat

When a numeric field's held stepper arrow next repeats, in monotonic seconds.

Instances

Instances details
Enum Slot Source # 
Instance details

Defined in NanoUI.Store

Methods

succ :: Slot -> Slot #

pred :: Slot -> Slot #

toEnum :: Int -> Slot #

fromEnum :: Slot -> Int #

enumFrom :: Slot -> [Slot] #

enumFromThen :: Slot -> Slot -> [Slot] #

enumFromTo :: Slot -> Slot -> [Slot] #

enumFromThenTo :: Slot -> Slot -> Slot -> [Slot] #

data Ease Source #

Instances

Instances details
Eq Ease Source # 
Instance details

Defined in NanoUI.Animation

Methods

(==) :: Ease -> Ease -> Bool #

(/=) :: Ease -> Ease -> Bool #

Show Ease Source # 
Instance details

Defined in NanoUI.Animation

Methods

showsPrec :: Int -> Ease -> ShowS #

show :: Ease -> String #

showList :: [Ease] -> ShowS #

data Animation Source #

Instances

Instances details
Eq Animation Source # 
Instance details

Defined in NanoUI.Animation

Show Animation Source # 
Instance details

Defined in NanoUI.Animation

data SpringParams Source #

Instances

Instances details
Eq SpringParams Source # 
Instance details

Defined in NanoUI.Animation

Show SpringParams Source # 
Instance details

Defined in NanoUI.Animation