nano-ui
Safe HaskellNone
LanguageGHC2024

NanoUI.Widgets.Custom

Description

Custom widgets and the reference widgets built on them.

customWidget takes a CustomWidgetSpec: a layout, optional measurement, drawing that sees hover and press state, an optional content key, a cursor, and damage slop. canvas is the short form for drawing into a laid-out rectangle with CanvasM. useDrag2D and useWheelDelta are gesture hooks for your own controls; knob and toggleSwitch show how they fit together.

Synopsis

Custom widgets

data CustomWidgetSpec a Source #

Complete specification for defining a custom widget.

Constructors

CustomWidgetSpec 

Fields

  • widgetLayout :: !Layout

    Flex layout constraints (widthheight sizing, minmax, alignment, padding).

  • widgetMeasure :: !(Maybe CustomMeasureFn)

    Optional intrinsic measurement hook for Fit or dynamic sizing.

  • widgetDraw :: !CustomDrawBuild

    Vector drawing procedure receiving interaction context and layout rect.

  • widgetContent :: !Int

    Content key: a number that changes whenever widgetDraw would draw something different from the state it reads (a value, a flag, a model revision; contentKey hashes numbers into one). A frame whose key, size, interaction state and metrics are unchanged neither rebuilds the ops nor repaints the widget (a widget that only moved has its ops translated), so key a drawing whose ops are expensive to build. The default 0 means no key: the ops are rebuilt every frame and compared, which repaints correctly whatever the drawing reads but pays for the rebuild. A stale key draws stale pixels, so derive it from everything the drawing reads, an animated value included: a key is believed while the widget animates, as a versioned drawing's version is.

  • widgetCursor :: !(Maybe (CustomDrawContext -> UiCursorKind))

    Optional custom mouse cursor when pointer is over the widget.

  • widgetFocusable :: !Bool

    Whether this widget accepts tab/keyboard focus.

  • widgetDamageSlop :: !Float

    Padding added to dirty rectangles (for shadows, glow, or drag handles).

  • widgetInteract :: !(Response -> CustomDrawContext -> Input -> (Response, a))

    Interaction hook. It receives the widget's resolved Response (hover, press, right-click, and clicks including one queued from a previous frame), the draw context and the input, and returns the final response and value.

defaultCustomWidgetSpec :: CustomWidgetSpec () Source #

Default configuration for a custom widget with standard hoverpressclick behavior.

customWidget :: forall (es :: [Effect]) a. Ui :> es => CustomWidgetSpec a -> Eff es (Response, a) Source #

Instantiates a custom widget from a CustomWidgetSpec.

Connects the widget into: - The two-pass layout arena (respecting widgetMeasure or layout constraints). - Off-heap vector drawing pipeline. Without a widgetContent key the draw function runs once a frame and the widget repaints when its ops change, so it may read anything; with one, an unchanged key skips both. - Interactive hit-testing, focus management, and custom cursor resolution. - Accurate damage region tracking with widgetDamageSlop.

customWidgetWithId :: forall (es :: [Effect]) a. Ui :> es => WidgetId -> CustomWidgetSpec a -> Eff es (Response, a) Source #

Instantiates a custom widget using an existing WidgetId.

contentKey :: [Float] -> Int Source #

A widgetContent key for a drawing whose output follows these numbers. Pass every value the drawing reads; 0 means "no key", so a hash that lands there becomes 1.

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

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

mkCustomDrawContext :: Context -> FontMetrics -> WidgetId -> IO CustomDrawContext Source #

Build the draw context a custom widget sees, resolving hoverpressfocus state for wid from the ambient context. One policy for state masking.

Canvas

data CanvasM a Source #

Monadic canvas builder that collects DrawOp vector operations efficiently.

Instances

Instances details
Applicative CanvasM Source # 
Instance details

Defined in NanoUI.Widgets.Custom

Methods

pure :: a -> CanvasM a #

(<*>) :: CanvasM (a -> b) -> CanvasM a -> CanvasM b #

liftA2 :: (a -> b -> c) -> CanvasM a -> CanvasM b -> CanvasM c #

(*>) :: CanvasM a -> CanvasM b -> CanvasM b #

(<*) :: CanvasM a -> CanvasM b -> CanvasM a #

Functor CanvasM Source # 
Instance details

Defined in NanoUI.Widgets.Custom

Methods

fmap :: (a -> b) -> CanvasM a -> CanvasM b #

(<$) :: a -> CanvasM b -> CanvasM a #

Monad CanvasM Source # 
Instance details

Defined in NanoUI.Widgets.Custom

Methods

(>>=) :: CanvasM a -> (a -> CanvasM b) -> CanvasM b #

(>>) :: CanvasM a -> CanvasM b -> CanvasM b #

return :: a -> CanvasM a #

runCanvas :: CanvasM a -> SmallArray DrawOp Source #

Compile a CanvasM block into an immutable 'SmallArray DrawOp'.

canvas :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> (Rect -> CanvasM ()) -> Eff es Response Source #

Draw into a rectangle sized by the layout modifier. Use customWidget when the drawing needs hover or press state.

drawRect :: Rect -> Color -> CanvasM () Source #

Fill a solid rectangle.

drawRoundedRect :: Rect -> Float -> Color -> CanvasM () Source #

Fill a rounded rectangle with given corner radius.

drawCircle :: V2 -> Float -> Color -> CanvasM () Source #

Fill a solid circle at center with given radius.

drawStroke :: V2 -> V2 -> Float -> Color -> CanvasM () Source #

Stroke a straight segment between two points with thickness.

drawStrokeRoundedRect :: Rect -> Float -> Float -> Color -> CanvasM () Source #

Stroke a rounded rectangle border with given radius and stroke width.

drawStrokeCircle :: V2 -> Float -> Float -> Color -> CanvasM () Source #

Stroke a circular outline at center with given radius and stroke width.

drawStrokeAA :: V2 -> V2 -> Float -> Color -> CanvasM () Source #

Antialiased smooth stroke line between two points.

drawQuadGradient :: Rect -> Color -> Color -> Color -> Color -> CanvasM () Source #

Four-corner bilinear gradient fill (top-left, top-right, bottom-right, bottom-left).

drawLinearGradientH :: Rect -> Color -> Color -> CanvasM () Source #

Horizontal 2-color linear gradient fill (left to right).

drawLinearGradientV :: Rect -> Color -> Color -> CanvasM () Source #

Vertical 2-color linear gradient fill (top to bottom).

drawImage :: Rect -> ImageId -> Color -> CanvasM () Source #

Draw a textured image stretched over given rectangle.

drawImageUV :: Rect -> ImageId -> Float -> Float -> Float -> Float -> Color -> CanvasM () Source #

Draw a sub-region of a textured image with explicit UV texture coordinates.

drawText :: V2 -> AlignX -> AlignY -> Text -> Color -> CanvasM () Source #

Draw text positioned at a reference point with horizontal and vertical alignment.

Gestures

useDrag2D :: forall (es :: [Effect]). Ui :> es => Rect -> Eff es Drag2D Source #

Tracks pointer dragging across a 2D area (e.g. for color pickers, joysticks, canvas panning).

data Drag2D Source #

Result of a 2D drag gesture.

Constructors

Drag2D 

Fields

  • dragPosition :: !V2

    Current dragged pointer position clamped within bounds.

  • dragActive :: !Bool

    True while pointer is pressed and dragging is active.

  • dragDelta :: !V2

    Movement delta since previous frame.

Instances

Instances details
Eq Drag2D Source # 
Instance details

Defined in NanoUI.Widgets.Custom

Methods

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

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

Show Drag2D Source # 
Instance details

Defined in NanoUI.Widgets.Custom

useWheelDelta :: forall (es :: [Effect]). Ui :> es => Rect -> Eff es (Float, Float) Source #

Inspects mouse wheel scroll delta when pointer is hovering over bounds.

Reference widgets

knob :: forall (es :: [Effect]). Ui :> es => Float -> Float -> Float -> Eff es Float Source #

Rotary knob over [minV, maxV], 36 px across. Drag vertically, scroll, or use the arrow keys. Pass the current value; the result is the value after this frame.

knob' :: forall (es :: [Effect]). Ui :> es => Float -> Float -> Float -> Eff es (Response, Float) Source #

knobWith :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Float -> Float -> Float -> Float -> Eff es Float Source #

knob with a layout modifier and a diameter in pixels.

knobWith' :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Float -> Float -> Float -> Float -> Eff es (Response, Float) Source #

toggleSwitch :: forall (es :: [Effect]). Ui :> es => Bool -> Eff es Bool Source #

On/off switch. Pass the current state; the result is the state after this frame's click or Space/Enter.

toggleSwitch' :: forall (es :: [Effect]). Ui :> es => Bool -> Eff es (Response, Bool) Source #

toggleSwitchWith :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Bool -> Eff es Bool Source #

toggleSwitch with a layout modifier.

toggleSwitchWith' :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Bool -> Eff es (Response, Bool) Source #

circularProgress :: forall (es :: [Effect]). Ui :> es => Float -> Eff es () Source #

Progress ring for a fraction in [0, 1], 32 px across.

circularProgress' :: forall (es :: [Effect]). Ui :> es => Float -> Eff es Response Source #

circularProgressWith :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Float -> Float -> Eff es () Source #

circularProgress with a layout modifier and a diameter in pixels.

circularProgressWith' :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Float -> Float -> Eff es Response Source #

spinner :: forall (es :: [Effect]). Ui :> es => Eff es () Source #

An indeterminate loading indicator: a short accent arc turning over a faint ring, 18 px across. It keeps the frame loop running while it is on screen and repaints only its own rect.

spinner' :: forall (es :: [Effect]). Ui :> es => Eff es Response Source #

spinnerWith :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Float -> Eff es () Source #

spinner with a layout modifier and a diameter in pixels.

spinnerWith' :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Float -> Eff es Response Source #

progressBar :: forall (es :: [Effect]). Ui :> es => Float -> Eff es () Source #

Horizontal progress bar for a fraction in [0, 1]. It fills the available width at a fixed height.

progressBar' :: forall (es :: [Effect]). Ui :> es => Float -> Eff es Response Source #

progressBarWith :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Float -> Float -> Eff es () Source #

progressBar with a layout modifier and a bar height in pixels.

progressBarWith' :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Float -> Float -> Eff es Response Source #

sparkline :: forall (es :: [Effect]). Ui :> es => [Float] -> Eff es () Source #

A small line chart of the values, 80 by 24 px, scaled to their range.

sparkline' :: forall (es :: [Effect]). Ui :> es => [Float] -> Eff es Response Source #

sparklineWith :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Float -> Float -> [Float] -> Eff es () Source #

sparkline with a layout modifier and a width and height in pixels.

sparklineWith' :: forall (es :: [Effect]). Ui :> es => (Layout -> Layout) -> Float -> Float -> [Float] -> Eff es Response Source #