Core API¶
The nuiitivet package exposes the core primitives, layout widgets, and state management utilities.
nuiitivet
¶
nuiitivet core package.
This module is the single source of truth for all public core symbols (layout, widgets, state management, theming, animation, modifiers, ...).
Applications should not import from this package directly. Instead they pick a
UI design system root — currently only :mod:nuiitivet.material — which
re-exports everything here plus its own widgets::
import nuiitivet.material as nv
nv.Column(...) # core symbol, re-exported here
nv.Button(...) # material symbol
That single import is the whole supported surface.
Reaching into the internal modules below (nuiitivet.layout.column,
nuiitivet.widgeting.widget, ...) is unsupported and may break without notice.
InputFilterLike
module-attribute
¶
InputFilterLike = Union[InputFilter, Callable[[str], str]]
An :class:InputFilter, or a plain str -> str callable standing in for one.
RendererMode
module-attribute
¶
Renderer selection accepted by :meth:nuiitivet.runtime.app.App.run.
"auto": try the GPU first and silently fall back to software (raster) rendering when the GPU backend is unavailable. This is the default."gpu": require the GPU. Initialization or per-frame GPU failures raise :class:RendererErrorinstead of degrading, so remote/GPU-less environments surface a clear error rather than running unexpectedly slowly."cpu": always render in software (raster); the GPU is never touched. A raster frame that cannot be presented raises :class:RendererError.
Note that App.run always needs a display/window; truly headless environments
should render offscreen via :meth:App.render_to_png instead.
Column
¶
Column(children: Optional[Sequence[Widget]] = None, *, width: SizingLike = None, height: SizingLike = None, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, gap: Union[int, ObservableBase] = 0, main_alignment: str = 'start', cross_alignment: str = 'start', key: Optional[str] = None)
Bases: Widget
Layout children vertically.
From a data collection, or an observable of one: :meth:builder.
Initialize Column and configure layout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
children
|
Optional[Sequence[Widget]]
|
List of child widgets to arrange vertically. |
None
|
width
|
SizingLike
|
Column width. |
None
|
height
|
SizingLike
|
Column height. |
None
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the content. |
0
|
gap
|
Union[int, ObservableBase]
|
Space between children in pixels. |
0
|
main_alignment
|
str
|
Vertical alignment of children. 'start', 'center', 'end', 'space-between', 'space-around', 'space-evenly'. |
'start'
|
cross_alignment
|
str
|
Horizontal alignment of children. 'start', 'center' or 'end'. |
'start'
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/column.py
builder
classmethod
¶
builder(items: ItemsLike, builder: BuilderFn, *, width: SizingLike = None, height: SizingLike = None, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, gap: int = 0, main_alignment: str = 'start', cross_alignment: str = 'start', key: Optional[str] = None) -> Column
Create a Column whose children are built from items.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
items
|
ItemsLike
|
Source data: a collection, or an observable of one -- the children then follow its changes. |
required |
builder
|
BuilderFn
|
Called as |
required |
width
|
SizingLike
|
Column width. |
None
|
height
|
SizingLike
|
Column height. |
None
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the content. |
0
|
gap
|
int
|
Space between children in pixels. |
0
|
main_alignment
|
str
|
Vertical alignment of children. 'start', 'center', 'end', 'space-between', 'space-around', 'space-evenly'. |
'start'
|
cross_alignment
|
str
|
Horizontal alignment of children. 'start', 'center' or 'end'. |
'start'
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/column.py
Row
¶
Row(children: Optional[List[Widget]] = None, *, width: SizingLike = None, height: SizingLike = None, padding: PaddingLike = 0, gap: Union[int, ObservableBase] = 0, main_alignment: str = 'start', cross_alignment: str = 'start', key: Optional[str] = None)
Bases: Widget
Layout children horizontally.
From a data collection, or an observable of one: :meth:builder.
Initialize Row and configure layout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
children
|
Optional[List[Widget]]
|
List of child widgets to arrange horizontally. |
None
|
width
|
SizingLike
|
Row width. Defaults to None (shrinkwrap). |
None
|
height
|
SizingLike
|
Row height. Defaults to None (shrinkwrap). |
None
|
padding
|
PaddingLike
|
Padding around the content. |
0
|
gap
|
Union[int, ObservableBase]
|
Space between children in pixels. |
0
|
main_alignment
|
str
|
Horizontal alignment of children. 'start', 'center', 'end', 'space-between', 'space-around', 'space-evenly'. |
'start'
|
cross_alignment
|
str
|
Vertical alignment of children. 'start', 'center' or 'end'. |
'start'
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/row.py
builder
classmethod
¶
builder(items: ItemsLike, builder: BuilderFn, *, width: SizingLike = None, height: SizingLike = None, padding: PaddingLike = 0, gap: int = 0, main_alignment: str = 'start', cross_alignment: str = 'start', key: Optional[str] = None) -> Row
Create a Row whose children are built from items.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
items
|
ItemsLike
|
Source data: a collection, or an observable of one -- the children then follow its changes. |
required |
builder
|
BuilderFn
|
Called as |
required |
width
|
SizingLike
|
Row width. |
None
|
height
|
SizingLike
|
Row height. |
None
|
padding
|
PaddingLike
|
Padding around the content. |
0
|
gap
|
int
|
Space between children in pixels. |
0
|
main_alignment
|
str
|
Horizontal alignment of children. 'start', 'center', 'end', 'space-between', 'space-around', 'space-evenly'. |
'start'
|
cross_alignment
|
str
|
Vertical alignment of children. 'start', 'center' or 'end'. |
'start'
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/row.py
Stack
¶
Stack(children: Sequence[Widget], *, width: SizingLike = None, height: SizingLike = None, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, alignment: AlignmentLike = 'top-left', key: Optional[str] = None)
Bases: Widget
Layout children on top of each other.
From a data collection, or an observable of one: :meth:builder.
Initialize the Stack layout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
children
|
Sequence[Widget]
|
List of widgets to stack on top of each other. |
required |
width
|
SizingLike
|
Stack width. |
None
|
height
|
SizingLike
|
Stack height. |
None
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the content. |
0
|
alignment
|
AlignmentLike
|
Default alignment for children. (horizontal, vertical) tuple or string like "top-left", "center". |
'top-left'
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/stack.py
builder
classmethod
¶
builder(items: ItemsLike, builder: BuilderFn, *, width: SizingLike = None, height: SizingLike = None, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, alignment: AlignmentLike = 'center', key: Optional[str] = None) -> 'Stack'
Create a Stack whose children are built from items.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
items
|
ItemsLike
|
Source data: a collection, or an observable of one -- the children then follow its changes. |
required |
builder
|
BuilderFn
|
Called as |
required |
width
|
SizingLike
|
Stack width. |
None
|
height
|
SizingLike
|
Stack height. |
None
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the content. |
0
|
alignment
|
AlignmentLike
|
Default alignment for children. (horizontal, vertical) tuple or string like "top-left", "center". |
'center'
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/stack.py
Container
¶
Container(child: Optional[Widget] = None, *, width: SizingLike = None, height: SizingLike = None, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, alignment: Union[str, Tuple[str, str]] = 'start', key: Optional[str] = None)
Bases: Widget
Lightweight layout-only Container.
This Container is a minimal single-child layout box. It intentionally does not perform background/shadow/border drawing or clipping.
Initialize the Container.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
child
|
Optional[Widget]
|
The child widget to be placed inside the container. |
None
|
width
|
SizingLike
|
The preferred width of the container. Defaults to None (shrinkwrap). |
None
|
height
|
SizingLike
|
The preferred height of the container. Defaults to None (shrinkwrap). |
None
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding to apply around the child. Can be a single integer, a 2-tuple (horizontal, vertical), or a 4-tuple (left, top, right, bottom). |
0
|
alignment
|
Union[str, Tuple[str, str]]
|
How to align the child within the container. Defaults to "start". Can be a string (e.g., "center") or a tuple (horizontal, vertical). |
'start'
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/container.py
Flow
¶
Flow(children: Optional[Sequence[Widget]] = None, *, main_gap: int = 0, cross_gap: int = 0, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, main_alignment: str = 'start', run_alignment: str = 'start', cross_alignment: str = 'start', width: SizingLike = None, height: SizingLike = None, key: Optional[str] = None)
Bases: Widget
Layout children in rows that wrap.
Arranges children in a horizontal run, wrapping to a new line when the line runs out of space.
From a data collection, or an observable of one: :meth:builder.
Initialize Flow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
children
|
Optional[Sequence[Widget]]
|
Child widgets to arrange. |
None
|
main_gap
|
int
|
Space between children in a line, in pixels. |
0
|
cross_gap
|
int
|
Space between lines, in pixels. |
0
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the content. |
0
|
main_alignment
|
str
|
Horizontal alignment of each line: 'start', 'center' or 'end'. |
'start'
|
run_alignment
|
str
|
Vertical alignment of the lines as a block: 'start', 'center' or 'end'. |
'start'
|
cross_alignment
|
str
|
Vertical alignment of a child within its line: 'start', 'center' or 'end'. |
'start'
|
width
|
SizingLike
|
Flow width. |
None
|
height
|
SizingLike
|
Flow height. |
None
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/flow.py
builder
classmethod
¶
builder(items: ItemsLike, builder: BuilderFn, *, main_gap: int = 0, cross_gap: int = 0, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, main_alignment: str = 'start', run_alignment: str = 'start', cross_alignment: str = 'start', width: SizingLike = None, height: SizingLike = None, key: Optional[str] = None) -> 'Flow'
Create a Flow whose children are built from items.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
items
|
ItemsLike
|
Source data: a collection, or an observable of one -- the children then follow its changes. |
required |
builder
|
BuilderFn
|
Called as |
required |
main_gap
|
int
|
Space between children in a line, in pixels. |
0
|
cross_gap
|
int
|
Space between lines, in pixels. |
0
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the content. |
0
|
main_alignment
|
str
|
Horizontal alignment of each line: 'start', 'center' or 'end'. |
'start'
|
run_alignment
|
str
|
Vertical alignment of the lines as a block: 'start', 'center' or 'end'. |
'start'
|
cross_alignment
|
str
|
Vertical alignment of a child within its line: 'start', 'center' or 'end'. |
'start'
|
width
|
SizingLike
|
Flow width. |
None
|
height
|
SizingLike
|
Flow height. |
None
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/flow.py
UniformFlow
¶
UniformFlow(children: Optional[Sequence[Widget]] = None, *, columns: Optional[int] = None, max_column_width: Optional[int] = None, aspect_ratio: Optional[float] = None, main_gap: int = 0, cross_gap: int = 0, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, main_alignment: str = 'start', run_alignment: str = 'start', item_alignment: AlignValue = 'start', width: SizingLike = None, height: SizingLike = None, key: Optional[str] = None)
Bases: Widget
Layout children in a uniform grid.
This layout arranges children into columns with equal width. A row is as
tall as its tallest child measures; a row whose children all have a "wt"
height also takes a share of the height the other rows leave.
From a data collection, or an observable of one: :meth:builder.
Initialize UniformFlow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
children
|
Optional[Sequence[Widget]]
|
Child widgets to arrange. |
None
|
columns
|
Optional[int]
|
Number of columns. Takes precedence over max_column_width. |
None
|
max_column_width
|
Optional[int]
|
Widest a column may get, in pixels; as many columns as fit the available width are used. With neither this nor columns, every child sits in one row. |
None
|
aspect_ratio
|
Optional[float]
|
Cell width divided by cell height; sets a minimum cell height from the column width. |
None
|
main_gap
|
int
|
Space between columns, in pixels. |
0
|
cross_gap
|
int
|
Space between rows, in pixels. |
0
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the content. |
0
|
main_alignment
|
str
|
Horizontal alignment of the grid: 'start', 'center' or 'end'. |
'start'
|
run_alignment
|
str
|
Vertical alignment of the grid: 'start', 'center' or 'end'. |
'start'
|
item_alignment
|
AlignValue
|
Where a child sits in its cell: one value for both
axes, or a |
'start'
|
width
|
SizingLike
|
UniformFlow width. |
None
|
height
|
SizingLike
|
UniformFlow height. |
None
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/uniform_flow.py
row_tracks
property
¶
Each row's (offset, length) from the last layout, relative to the flow; empty before one.
column_tracks
property
¶
Each column's (offset, length) from the last layout, relative to the flow; empty before one.
builder
classmethod
¶
builder(items: ItemsLike, builder: BuilderFn, *, columns: Optional[int] = None, max_column_width: Optional[int] = None, aspect_ratio: Optional[float] = None, main_gap: int = 0, cross_gap: int = 0, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, main_alignment: str = 'start', run_alignment: str = 'start', item_alignment: AlignValue = 'start', width: SizingLike = None, height: SizingLike = None, key: Optional[str] = None) -> 'UniformFlow'
Create a UniformFlow whose children are built from items.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
items
|
ItemsLike
|
Source data: a collection, or an observable of one -- the children then follow its changes. |
required |
builder
|
BuilderFn
|
Called as |
required |
columns
|
Optional[int]
|
Number of columns. Takes precedence over max_column_width. |
None
|
max_column_width
|
Optional[int]
|
Widest a column may get, in pixels; as many columns as fit the available width are used. With neither this nor columns, every child sits in one row. |
None
|
aspect_ratio
|
Optional[float]
|
Cell width divided by cell height; sets a minimum cell height from the column width. |
None
|
main_gap
|
int
|
Space between columns, in pixels. |
0
|
cross_gap
|
int
|
Space between rows, in pixels. |
0
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the content. |
0
|
main_alignment
|
str
|
Horizontal alignment of the grid: 'start', 'center' or 'end'. |
'start'
|
run_alignment
|
str
|
Vertical alignment of the grid: 'start', 'center' or 'end'. |
'start'
|
item_alignment
|
AlignValue
|
Where a child sits in its cell: one value for both
axes, or a |
'start'
|
width
|
SizingLike
|
UniformFlow width. |
None
|
height
|
SizingLike
|
UniformFlow height. |
None
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/uniform_flow.py
Grid
¶
Grid(children: Optional[Sequence[Widget]], rows: Optional[Sequence[SizingLike]], columns: Optional[Sequence[SizingLike]], *, width: SizingLike = None, height: SizingLike = None, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, row_gap: int = 0, column_gap: int = 0, key: Optional[str] = None)
Bases: Widget
Two-dimensional layout container with explicit tracks.
With areas laid out by name: :meth:named_areas.
Initialize the Grid layout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
children
|
Optional[Sequence[Widget]]
|
List of GridItems to display. |
required |
rows
|
Optional[Sequence[SizingLike]]
|
One track size per row: an |
required |
columns
|
Optional[Sequence[SizingLike]]
|
One track size per column; same forms as |
required |
width
|
SizingLike
|
Grid container width. |
None
|
height
|
SizingLike
|
Grid container height. |
None
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the grid content. |
0
|
row_gap
|
int
|
Vertical gap between rows. |
0
|
column_gap
|
int
|
Horizontal gap between columns. |
0
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/grid.py
row_tracks
property
¶
Each row's (offset, length) from the last layout, relative to the grid; empty before one.
column_tracks
property
¶
Each column's (offset, length) from the last layout, relative to the grid; empty before one.
named_areas
classmethod
¶
named_areas(children: Sequence[Widget], areas: Sequence[Sequence[str]], *, width: SizingLike = None, height: SizingLike = None, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, row_gap: int = 0, column_gap: int = 0, rows: Optional[Sequence[SizingLike]] = None, columns: Optional[Sequence[SizingLike]] = None) -> Grid
Create a Grid using named template areas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
children
|
Sequence[Widget]
|
List of child widgets (usually GridItem.named_area). |
required |
areas
|
Sequence[Sequence[str]]
|
2D list of area names (e.g. [["header", "header"], ["sidebar", "content"]]). |
required |
width
|
SizingLike
|
Grid width. |
None
|
height
|
SizingLike
|
Grid height. |
None
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Grid padding. |
0
|
row_gap
|
int
|
Gap between rows. |
0
|
column_gap
|
int
|
Gap between columns. |
0
|
rows
|
Optional[Sequence[SizingLike]]
|
Explicit row sizing overrides. |
None
|
columns
|
Optional[Sequence[SizingLike]]
|
Explicit column sizing overrides. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Grid |
Grid
|
A configured Grid instance. |
Source code in src/nuiitivet/layout/grid.py
placement_of
¶
placement_of(child: Widget) -> Tuple[int, int, int, int]
The (row, column, row_span, column_span) a child occupies.
Raises TypeError for a child that is not a GridItem and
ValueError for one placed nowhere.
Source code in src/nuiitivet/layout/grid.py
GridItem
¶
GridItem(child: Widget, row: Optional[GridIndex] = None, column: Optional[GridIndex] = None, *, width: SizingLike = None, height: SizingLike = None, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, alignment: Union[str, Tuple[str, str]] = 'start', key: Optional[str] = None)
Bases: Container
Annotate a child with explicit grid placement data.
Into an area of :meth:Grid.named_areas: :meth:named_area.
Initialize the GridItem wrapper.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
child
|
Widget
|
The widget to place in the grid. |
required |
row
|
Optional[GridIndex]
|
Row index or (start, end) tuple. 0-based. |
None
|
column
|
Optional[GridIndex]
|
Column index or (start, end) tuple. 0-based. |
None
|
width
|
SizingLike
|
Override width. |
None
|
height
|
SizingLike
|
Override height. |
None
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the child within the grid cell. |
0
|
alignment
|
Union[str, Tuple[str, str]]
|
Alignment within the grid cell. Defaults to "start". |
'start'
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/grid.py
named_area
classmethod
¶
named_area(child: Widget, name: str, *, width: SizingLike = None, height: SizingLike = None, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, alignment: Union[str, Tuple[str, str]] = 'start') -> GridItem
Create a GridItem placed in a named template area.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
child
|
Widget
|
The child widget to place. |
required |
name
|
str
|
The area name matching a name in Grid.named_areas(). |
required |
width
|
SizingLike
|
Override width. |
None
|
height
|
SizingLike
|
Override height. |
None
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding around the child within the grid cell. |
0
|
alignment
|
Union[str, Tuple[str, str]]
|
Alignment within the grid cell. Defaults to "start". |
'start'
|
Returns:
| Name | Type | Description |
|---|---|---|
GridItem |
GridItem
|
The wrapped widget with area information. |
Source code in src/nuiitivet/layout/grid.py
Spacer
¶
Spacer(*, width: SizingLike = 0, height: SizingLike = 0, padding: PaddingLike = 0, key: Optional[str] = None)
Bases: Widget
Invisible widget that reserves space.
A fixed size reserves exactly that much; a weight ("wt") takes the
space its parent has left over.
Initialize a Spacer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
width
|
SizingLike
|
Width to reserve: a fixed size, or a weight ( |
0
|
height
|
SizingLike
|
Height to reserve, in the same forms as width. |
0
|
padding
|
PaddingLike
|
Insets from the allocated rect to the reserved space. |
0
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/spacer.py
preferred_size
¶
preferred_size(max_width: Optional[int] = None, max_height: Optional[int] = None) -> Tuple[int, int]
Return preferred size based on Sizings, plus padding.
- fixed: return the fixed value
- auto/weight: return 0 (minimum size, parent will allocate)
Source code in src/nuiitivet/layout/spacer.py
CrossAligned
¶
CrossAligned(child: Optional[Widget], alignment: str, *, padding: PaddingLike = 0, key: Optional[str] = None)
Bases: Widget
Layout wrapper that overrides cross-axis alignment in Row/Column.
This sets cross_align metadata on the wrapper. Row/Column may read
this to override their cross_alignment for this child only.
Initialize the CrossAligned wrapper.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
child
|
Optional[Widget]
|
The child widget to wrap. |
required |
alignment
|
str
|
The cross-axis alignment to apply to this child. One of "start", "center" or "end". |
required |
padding
|
PaddingLike
|
Insets from the allocated rect to the child. |
0
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/cross_aligned.py
Deck
¶
Deck(children: Optional[Sequence[Widget]] = None, index: Union[int, ObservableBase[int]] = 0, *, width: SizingLike = None, height: SizingLike = None, padding: Union[int, Tuple[int, int], Tuple[int, int, int, int]] = 0, key: Optional[str] = None)
Bases: Widget
Display only one child at a time.
All children remain mounted (state preserved), but only the selected child is visible and rendered.
Usage
Deck(children=[HomeTab(), SearchTab(), ProfileTab()], index=0)
For type-safe index, use IntEnum: class Section(IntEnum): HOME = 0 SEARCH = 1 Deck(children=[...], index=Section.HOME)
Initialize the Deck layout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
children
|
Optional[Sequence[Widget]]
|
A list of child widgets. All are mounted, but only one is visible. |
None
|
index
|
Union[int, ObservableBase[int]]
|
The index of the child to display. Can be an integer or any
read-observable of int — a plain |
0
|
width
|
SizingLike
|
The preferred width of the container. Defaults to None. |
None
|
height
|
SizingLike
|
The preferred height of the container. Defaults to None. |
None
|
padding
|
Union[int, Tuple[int, int], Tuple[int, int, int, int]]
|
Padding to apply around the visible child. Defaults to 0. |
0
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/deck.py
current_index
property
¶
The selected child index, clamped to the children that exist.
Resolved from the observable on every read rather than served from the
cache the subscription maintains. The subscription is mount-scoped -- it
exists to call mark_needs_layout, which only means anything in a
tree -- so without this a Deck that had not been mounted yet, or had been
taken out, would report a stale index to code that is entitled to ask.
on_mount
¶
Follow the index observable for as long as this Deck is in the tree.
The observable belongs to the app and outlives this widget, so a bare
subscribe in the constructor left it holding _on_index_changed
forever -- the leak this framework's bind() convention exists to
prevent. A dispose() method used to sit here doing the cleanup, and
never ran: Widget has no dispose hook for anything to call it
from.
Source code in src/nuiitivet/layout/deck.py
set_index
¶
Set the selected child index (for non-Observable usage).
Source code in src/nuiitivet/layout/deck.py
focus_traversal_children
¶
focus_traversal_children() -> List[Widget]
Return only the selected page, so Tab skips the pages behind it.
The index addresses the post-expansion list — the same list
paint and hit_test work on — so it is resolved on every call and
stays correct when a ForEach child changes its item count.
Source code in src/nuiitivet/layout/deck.py
layout
¶
Layout all children (to preserve state), position selected child.
Source code in src/nuiitivet/layout/deck.py
paint
¶
Paint only the selected child.
Source code in src/nuiitivet/layout/deck.py
hit_test
¶
Only allow hit testing on the selected child.
The Deck itself never becomes the hit target (S = none); it defers to the selected child only (C descends into one child), routed through the shared hit-participation helper.
Source code in src/nuiitivet/layout/deck.py
Collapsible
¶
Collapsible(child: Optional[Widget] = None, *, opened: Union[bool, ObservableBase[bool]] = True, motion: Motion = _DEFAULT_MOTION, motion_out: Optional[Motion] = None, axis: Axis = 'both', alignment: Union[str, Tuple[str, str]] = 'top-left', padding: PaddingLike = 0, key: Optional[str] = None)
Bases: FocusTraversalBlocker, Widget
Single-child widget that animates its layout size open and closed.
The child is always mounted and laid out at its own natural size; the allocated rectangle reported to the parent is interpolated per axis. The animated rectangle is clipped internally, so the child never overflows its allocated bounds.
preferred_size only reports that interpolated rectangle: measuring is
speculative and repeated, so it never retargets. layout owns the
animation -- both the retarget and the first-layout snap to the initial
state.
Initialize a Collapsible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
child
|
Optional[Widget]
|
The |
None
|
opened
|
Union[bool, ObservableBase[bool]]
|
|
True
|
motion
|
Motion
|
Base motion used for both open (enter) and close (exit). |
_DEFAULT_MOTION
|
motion_out
|
Optional[Motion]
|
Optional motion that overrides only the close (exit)
direction. When omitted, |
None
|
axis
|
Axis
|
Which axis/axes to animate ( |
'both'
|
alignment
|
Union[str, Tuple[str, str]]
|
Alignment of the child within the animated rectangle. |
'top-left'
|
padding
|
PaddingLike
|
Insets from the allocated rect to the animated area. |
0
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/collapsible.py
blocks_focus_traversal
property
¶
Keep the child out of the Tab sequence while the collapsible is closed.
The child stays mounted and laid out at its natural size while closed,
so without this its focusable widgets would remain Tab stops behind the
clip. Traversal follows the opened flag rather than the size
animation: the content becomes reachable as soon as it starts expanding
(it is on screen by then) and unreachable as soon as it starts
collapsing.
preferred_size
¶
preferred_size(max_width: Optional[int] = None, max_height: Optional[int] = None) -> Tuple[int, int]
Report the current (possibly interpolated) outer size.
Measuring never touches the animation: the reported size follows
whatever layout last resolved. The constraints are remembered so
the following layout measures the child the same way.
Source code in src/nuiitivet/layout/collapsible.py
VerticalScrollable
¶
VerticalScrollable(child: Widget, *, controller: Optional[ScrollController] = None, scrollbar_visible: ScrollbarVisibleLike = True, width: SizingLike = None, height: SizingLike = None, padding: PaddingLike = 0, scrollbar_behavior: Optional[ScrollbarBehavior] = None, scrollbar_style: Optional[ScrollbarStyle] = None, style: Optional[ScrollableStyle] = None, key: Optional[str] = None)
Bases: _ScrollableBase
Scrolls its child along the vertical axis.
Source code in src/nuiitivet/layout/scrollable.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | |
HorizontalScrollable
¶
HorizontalScrollable(child: Widget, *, controller: Optional[ScrollController] = None, scrollbar_visible: ScrollbarVisibleLike = True, width: SizingLike = None, height: SizingLike = None, padding: PaddingLike = 0, scrollbar_behavior: Optional[ScrollbarBehavior] = None, scrollbar_style: Optional[ScrollbarStyle] = None, style: Optional[ScrollableStyle] = None, key: Optional[str] = None)
Bases: _ScrollableBase
Scrolls its child along the horizontal axis.
Source code in src/nuiitivet/layout/scrollable.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | |
ForEach
¶
ForEach(items: ItemsLike, builder: BuilderFn, *, key_fn: Optional[Callable[[Any, int], Any]] = None, key: Optional[str] = None)
Bases: ComposableWidget
Initialize the ForEach data provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
items
|
ItemsLike
|
The source data collection. Can be an Iterable, an Observable, or an object with a .value attribute (checking value first). |
required |
builder
|
BuilderFn
|
A function that takes (item, index) and returns a Widget. |
required |
key_fn
|
Optional[Callable[[Any, int], Any]]
|
An optional function |
None
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload
(this ForEach node itself — not the per-item identity, which is
|
None
|
Source code in src/nuiitivet/layout/for_each.py
ScrollbarBehavior
dataclass
¶
ScrollbarBehavior(auto_hide: bool = True, hide_delay: float = 1.0, fade_duration: float = 0.15, hide_threshold: float = 0.25, track_click_behavior: str = 'jump', interactive: bool = True, hit_slop: Optional[int] = None)
Immutable behavior configuration for scrollbar widgets.
MenuBar
¶
MenuBar(items: Sequence[MenuEntry], *, style: Optional[MenuBarStyle] = None)
The application menu bar model: the root of the declarative menu tree.
Registered on the App (App(menu=nv.MenuBar([...]))) and replaced
wholesale via app.menu = .... Structure is not observable — entry
properties (label / enabled / checked) may be Observables, but adding
or removing entries means assigning a new model.
Initialize MenuBar.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
items
|
Sequence[MenuEntry]
|
Top-level entries. Bar entries are usually submenus
( |
required |
style
|
Optional[MenuBarStyle]
|
Optional per-instance style; |
None
|
Source code in src/nuiitivet/menubar/model.py
MenuBarArea
¶
Bases: MenuBarSlotBase
Marks where the registered menu bar renders, instead of the default spot.
Place it anywhere in the tree — typically inside a CustomChrome header
row — and the App-registered menu model renders there; the App's automatic
insertion below the chrome is suppressed. Menu definitions, callbacks and
shortcuts are unaffected by placement.
With no menu registered it renders nothing, so conditional menus are fine.
If several MenuBarArea widgets are mounted at once, only the first one
renders (a warning is logged).
On macOS the menu goes to the global menu bar (NSMenu) and the area
collapses to zero size — a chrome written around a MenuBarArea
degrades to a plain title bar with no platform branching.
Source code in src/nuiitivet/menubar/slots.py
MenuBarStyle
dataclass
¶
MenuBarStyle(bar_height: int = 34, bar_horizontal_padding: int = 4, item_horizontal_padding: int = 10, item_gap: int = 2, item_corner_radius: int = 6, label_size: int = 13, popup_corner_radius: int = 8, popup_min_width: int = 180, bar_background: Optional[ColorSpec] = None, bar_foreground: Optional[ColorSpec] = None, bar_disabled_foreground: Optional[ColorSpec] = None, bar_open_background: Optional[ColorSpec] = None, bar_state_layer: Optional[ColorSpec] = None, popup_background: Optional[ColorSpec] = None, popup_foreground: Optional[ColorSpec] = None, popup_accelerator: Optional[ColorSpec] = None, popup_disabled_foreground: Optional[ColorSpec] = None, popup_state_layer: Optional[ColorSpec] = None, popup_divider: Optional[ColorSpec] = None)
Immutable visual style for the in-app menu bar.
Holds geometry plus optional per-instance color overrides, mirroring
:class:~nuiitivet.scrolling.ScrollbarStyle: the app-wide default palette
is supplied by the design system via
:class:~nuiitivet.menubar.MenuBarThemeData, and the nullable ColorSpec
fields here override it per instance. A None color falls back to the
theme. Attach it to the model root: MenuBar(items, style=...).
On macOS none of this applies — the global menu bar is rendered by the OS
(see :mod:nuiitivet.menubar.nsmenu).
Attributes:
| Name | Type | Description |
|---|---|---|
bar_height |
int
|
Height of the horizontal bar in pixels. |
bar_horizontal_padding |
int
|
Padding at the left/right ends of the bar. |
item_horizontal_padding |
int
|
Horizontal padding inside each top-level item. |
item_gap |
int
|
Gap between top-level items. |
item_corner_radius |
int
|
Corner radius of the top-level item highlight. |
label_size |
int
|
Font size of top-level item labels. |
popup_corner_radius |
int
|
Corner radius of popup surfaces. |
popup_min_width |
int
|
Minimum popup width in pixels. |
bar_background |
Optional[ColorSpec]
|
Per-instance override ( |
copy_with
¶
merged_palette
¶
merged_palette(theme_data: Optional[MenuBarThemeData]) -> MenuBarThemeData
The effective palette: theme data with this style's overrides applied.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
theme_data
|
Optional[MenuBarThemeData]
|
App-wide palette from the active theme, or |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
MenuBarThemeData
|
class: |
MenuBarThemeData
|
color field on this style is replaced by that override. |
Source code in src/nuiitivet/menubar/style.py
MenuBarThemeData
dataclass
¶
MenuBarThemeData(bar_background: ColorSpec = ('#000000', 0.04), bar_foreground: ColorSpec = ('#000000', 0.87), bar_disabled_foreground: ColorSpec = ('#000000', 0.38), bar_open_background: ColorSpec = ('#000000', 0.12), bar_state_layer: ColorSpec = '#000000', popup_background: ColorSpec = '#FFFFFF', popup_foreground: ColorSpec = ('#000000', 0.87), popup_accelerator: ColorSpec = ('#000000', 0.6), popup_disabled_foreground: ColorSpec = '#000000', popup_state_layer: ColorSpec = '#000000', popup_divider: ColorSpec = ('#000000', 0.12))
App-wide themeable colors for the menu bar, resolved at paint time.
The defaults are neutral, design-system-agnostic literals so that a bare
MenuBarThemeData() is usable even when no design system is registered.
Attributes:
| Name | Type | Description |
|---|---|---|
bar_background |
ColorSpec
|
Background of the horizontal bar. |
bar_foreground |
ColorSpec
|
Label color of top-level bar items. |
bar_disabled_foreground |
ColorSpec
|
Label color of disabled top-level items. |
bar_open_background |
ColorSpec
|
Background of the top-level item whose menu is open. |
bar_state_layer |
ColorSpec
|
Hover/press state-layer color for bar items. |
popup_background |
ColorSpec
|
Popup container background. |
popup_foreground |
ColorSpec
|
Popup item label color. |
popup_accelerator |
ColorSpec
|
Accelerator text color in popup items. |
popup_disabled_foreground |
ColorSpec
|
Base color for disabled popup items. |
popup_state_layer |
ColorSpec
|
Hover/press/focus state-layer color for popup items. |
popup_divider |
ColorSpec
|
Separator line color inside popups. |
copy_with
¶
MenuEntry
¶
MenuEntry(label: ObservableStr = '', *, on_select: Optional[VoidCallback] = None, shortcut: Optional[ShortcutLike] = None, enabled: ObservableBool = True, checked: Optional[MutableObservableBase[bool]] = None, submenu: Optional[Sequence['MenuEntry']] = None, _role: MenuRole = NONE, _separator: bool = False)
One entry in a declarative menu model.
A single type covers all roles:
- Action:
MenuEntry("Open...", on_select=..., shortcut="Accel+O") - Submenu:
MenuEntry("File", submenu=[...])— top-level bar entries are simply entries with asubmenu; nesting is unlimited. - Separator:
MenuEntry.separator() - Standard item:
MenuEntry.quit(),close_window(),minimize(),maximize(),restore(),full_screen()— prebuilt entries whose activation calls a built-in App/Window method.
label and enabled may be Observables and propagate live to
whichever surface renders the model. checked (presence makes the entry
checkable) must be a writable Observable: activation toggles it before
on_select runs.
Initialize MenuEntry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
ObservableStr
|
Entry label; a plain string or an Observable. |
''
|
on_select
|
Optional[VoidCallback]
|
Called with no arguments when the entry is activated. May be
sync or async. Exactly one of |
None
|
shortcut
|
Optional[ShortcutLike]
|
Accelerator gesture, as a spec string ( |
None
|
enabled
|
ObservableBool
|
Whether the entry can be activated; a bool or an Observable. |
True
|
checked
|
Optional[MutableObservableBase[bool]]
|
Writable Observable holding the check state. Presence makes
the entry checkable; activation toggles the value, then calls
|
None
|
submenu
|
Optional[Sequence['MenuEntry']]
|
Child entries. Mutually exclusive with |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the combination of arguments is invalid. |
Source code in src/nuiitivet/menus/model.py
resolved_label
¶
resolved_enabled
¶
separator
classmethod
¶
quit
classmethod
¶
quit(*, label: Optional[ObservableStr] = None, shortcut: Optional[ShortcutLike] = None, enabled: ObservableBool = True) -> 'MenuEntry'
Exit the application (calls app.exit()).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
Optional[ObservableStr]
|
Entry label. Defaults to "Quit" on macOS, "Exit" elsewhere. |
None
|
shortcut
|
Optional[ShortcutLike]
|
Accelerator gesture. Defaults to |
None
|
enabled
|
ObservableBool
|
Whether the entry can be activated; a bool or an Observable. |
True
|
Source code in src/nuiitivet/menus/model.py
close_window
classmethod
¶
close_window(*, label: ObservableStr = 'Close Window', shortcut: Optional[ShortcutLike] = 'Accel+W', enabled: ObservableBool = True) -> 'MenuEntry'
Close the window (calls window.close()).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
ObservableStr
|
Entry label. Defaults to "Close Window". |
'Close Window'
|
shortcut
|
Optional[ShortcutLike]
|
Accelerator gesture. Defaults to |
'Accel+W'
|
enabled
|
ObservableBool
|
Whether the entry can be activated; a bool or an Observable. |
True
|
Source code in src/nuiitivet/menus/model.py
minimize
classmethod
¶
minimize(*, label: ObservableStr = 'Minimize', shortcut: Optional[ShortcutLike] = None, enabled: ObservableBool = True) -> 'MenuEntry'
Minimize the window (calls window.minimize()).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
ObservableStr
|
Entry label. Defaults to "Minimize". |
'Minimize'
|
shortcut
|
Optional[ShortcutLike]
|
Accelerator gesture. Defaults to |
None
|
enabled
|
ObservableBool
|
Whether the entry can be activated; a bool or an Observable. |
True
|
Source code in src/nuiitivet/menus/model.py
maximize
classmethod
¶
maximize(*, label: Optional[ObservableStr] = None, shortcut: Optional[ShortcutLike] = None, enabled: ObservableBool = True) -> 'MenuEntry'
Maximize / zoom the window (calls window.maximize()).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
Optional[ObservableStr]
|
Entry label. Defaults to "Zoom" on macOS, "Maximize" elsewhere. |
None
|
shortcut
|
Optional[ShortcutLike]
|
Accelerator gesture. None by default. |
None
|
enabled
|
ObservableBool
|
Whether the entry can be activated; a bool or an Observable. |
True
|
Source code in src/nuiitivet/menus/model.py
restore
classmethod
¶
restore(*, label: ObservableStr = 'Restore', shortcut: Optional[ShortcutLike] = None, enabled: ObservableBool = True) -> 'MenuEntry'
Restore the window (calls window.restore()).
The way back from :meth:full_screen, :meth:maximize, and
:meth:minimize: exits full screen, or restores the pre-maximize
size, or brings a minimized window back.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
ObservableStr
|
Entry label. Defaults to "Restore". |
'Restore'
|
shortcut
|
Optional[ShortcutLike]
|
Accelerator gesture. None by default. |
None
|
enabled
|
ObservableBool
|
Whether the entry can be activated; a bool or an Observable. |
True
|
Source code in src/nuiitivet/menus/model.py
full_screen
classmethod
¶
full_screen(*, label: ObservableStr = 'Full Screen', shortcut: Optional[ShortcutLike] = None, enabled: ObservableBool = True) -> 'MenuEntry'
Toggle full screen (calls window.full_screen()).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
ObservableStr
|
Entry label. Defaults to "Full Screen". |
'Full Screen'
|
shortcut
|
Optional[ShortcutLike]
|
Accelerator gesture. None by default. |
None
|
enabled
|
ObservableBool
|
Whether the entry can be activated; a bool or an Observable. |
True
|
Source code in src/nuiitivet/menus/model.py
MenuRole
¶
Bases: Enum
Built-in command a standard :class:MenuEntry invokes.
A role entry needs no on_select: activating it calls the mapped
built-in method (see nuiitivet.menubar.controller). Roles are also what
the macOS bridge will use to relocate items to their conventional places
(e.g. Quit into the application menu).
Sizing
dataclass
¶
How a widget sizes itself along one axis.
Construct with :meth:fixed, :meth:auto or :meth:weight; wherever a
sizing is accepted, a number means fixed, "auto" auto, and "wt" /
"wt2" a weight.
Widget
¶
Widget(*, width: Union[SizingLike, ReadOnlyObservableProtocol] = None, height: Union[SizingLike, ReadOnlyObservableProtocol] = None, padding: Union[PaddingLike, ReadOnlyObservableProtocol] = None, max_children: Optional[int] = None, overflow_policy: str = 'none', key: Optional[str] = None)
Bases: BindingHostMixin, LifecycleHostMixin, InputHubMixin, ChildContainerMixin, WidgetKernel
Leaf-friendly widget base composed from mixins.
This class intentionally does not participate in build/recomposition.
Widgets that need build()/rebuild()/scope() must inherit
ComposableWidget.
Source code in src/nuiitivet/widgeting/widget.py
editable_parameters
classmethod
¶
The constructor keywords layout edit mode edits from its bar, and the type each value is picked from.
The mode builds a box per keyword named here from the type: a class
with presets offers its classmethods that take only optional
Literal arguments (ButtonStyle.filled("m")), or its uppercase
attributes (TypeScale.TITLE_LARGE). The sizes and spacing a drag
edits are read from the constructor's signature and are not listed. A
widget with nothing for the bar returns an empty mapping.
Source code in src/nuiitivet/widgeting/widget.py
mark_needs_layout
¶
Mark this widget as needing layout recalculation.
Source code in src/nuiitivet/widgeting/widget.py
find_ancestor
¶
Find the nearest ancestor of the specified type.
Traverses up the widget tree looking for an ancestor that matches the given type. This is used to implement context lookup patterns like Navigator.of(context).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
widget_type
|
Type[T]
|
The type of widget to find. |
required |
Returns:
| Type | Description |
|---|---|
Optional[T]
|
The nearest ancestor of the specified type, or None if not found. |
Example
navigator = self.find_ancestor(Navigator) if navigator: navigator.push(...)
Source code in src/nuiitivet/widgeting/widget.py
modifier
¶
modifier(modifier: Union[Modifier, ModifierElement]) -> Widget
Apply a modifier to this widget, returning the wrapped result.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
modifier
|
Union[Modifier, ModifierElement]
|
The modifier (or modifier element) to apply. |
required |
Returns:
| Type | Description |
|---|---|
Widget
|
The wrapped widget (e.g. ModifierBox) or the widget itself if modified in-place. |
Source code in src/nuiitivet/widgeting/widget.py
ComposableWidget
¶
Bases: BuilderHostMixin, Widget
Widget base that participates in build/recomposition.
Composition widgets can override build() and use scope() /
render_scope() for fine-grained recomposition.
Layout metadata is transparent: a
value declared on this widget wins, and an undeclared one is derived from
the widget its build() returned — so extracting a subtree into a
composable does not change how the tree lays out.
Source code in src/nuiitivet/widgeting/widget_builder.py
Box
¶
Box(child: Optional[Widget] = None, width: SizingLike = None, height: SizingLike = None, padding: PaddingLike = 0, background_color: Optional[ColorSpec] = None, border_width: float = 0, border_color: Optional[ColorSpec] = None, corner_radius: Union[float, Tuple[float, float, float, float]] = 0, shadows: ShadowLike = None, alignment: Union[str, Tuple[str, str]] = 'center', *, key: Optional[str] = None)
Bases: CachedPaintMixin, Widget
(Advanced) Low-level drawing primitive.
Note
Prefer using Modifiers (e.g. .background(), .border(), .shadows())
on a Container or other widgets. This widget is used internally
to implement those modifiers.
A widget that draws a box with optional background, border, and shadow.
Source code in src/nuiitivet/widgets/box.py
shadows
property
writable
¶
The shadow layers this box draws, ordered back to front.
visual_clip_rect
¶
Return the rect content is clipped to, in this widget's local coords.
None when the box clips nothing, which is the common case.
This publishes, under the name geometric readers probe for (see
nuiitivet._interaction.perception), the same answer paint and
:meth:hit_test already act on. Without it a child laid out outside
the box -- an oversized decorative shape trimmed to a corner, the idiom
that fakes a gradient -- keeps its full layout rect as far as anything
reading the tree geometrically is concerned, and so looks reachable at
coordinates where none of it is painted.
Derived from layout state rather than last_rect: an action settles
the tree by laying it out without painting, so paint state is stale
exactly when this is needed.
Source code in src/nuiitivet/widgets/box.py
corner_radii_pixels
¶
Return the resolved corner radii in pixels for the given size.
InputFilter
¶
Bases: ABC
A rule applied to text as the user types it.
Subclasses implement :meth:apply, which receives the value before the
edit and the value the edit proposes, and returns the value to accept.
Returning old rejects the edit outright; returning new accepts it
unchanged.
apply
abstractmethod
¶
Geometry
¶
Geometry(child: Widget, *, width: SizingLike = None, height: SizingLike = None, padding: PaddingLike = 0, key: Optional[str] = None)
Bases: Widget
Publishes this widget's own measured geometry to its subtree.
Transparent to layout: the single child receives this widget's own size.
Each layout pass publishes that size as an Observable[Size], read by
descendants via :meth:Geometry.of — bind it (mapped); a .value read at
build time is a one-time snapshot. Map it into a value widget, or drive a
Deck index for a structural switch::
class Panel(ComposableWidget):
def build(self) -> Widget:
size = Geometry.of(self).size
return Deck(
children=[_NarrowLayout(...), _WideLayout(...)],
index=size.map(lambda s: 1 if s.width >= 600 else 0),
)
Geometry(Panel())
The nearest ancestor provider wins, so wrapping a panel makes descendants
react to the panel, not the window; with no nearer provider, reads fall back
to the root Geometry the app installs at the window and track the window
size. The size is measured during layout and published between frames:
consumers see it one frame later, never a torn mix of old and new.
Wrap child, publishing this widget's measured size to its subtree.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
child
|
Widget
|
The single child laid out at this widget's own size. |
required |
width
|
SizingLike
|
Sizing for this widget ( |
None
|
height
|
SizingLike
|
Sizing for this widget; see |
None
|
padding
|
PaddingLike
|
Insets from the allocated rect to the child. |
0
|
key
|
Optional[str]
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/layout/geometry.py
size
property
¶
size: Observable[Size]
This widget's resolved (width, height), published between frames.
of
classmethod
¶
of(context: Widget) -> GeometryT
Return the nearest ancestor :class:Geometry (nearest provider wins).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
Widget
|
A widget in the subtree from which to search upward. |
required |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If called before |
Source code in src/nuiitivet/layout/geometry.py
preferred_size
¶
preferred_size(max_width: Optional[int] = None, max_height: Optional[int] = None) -> Tuple[int, int]
Report preferred size: own fixed sizing wins, else the child's.
A weight / "wt" sizing is not fixed, so the child's intrinsic
size is reported here and the parent's weight distribution then stretches
this widget to fill — which is what lets a filling Geometry measure
the space available to a content pane.
Source code in src/nuiitivet/layout/geometry.py
layout
¶
Lay the child out in the content rect, then queue this widget's own size.
Source code in src/nuiitivet/layout/geometry.py
paint
¶
Paint the child at this widget's own rect (transparent to paint).
Source code in src/nuiitivet/layout/geometry.py
Size
¶
Bases: NamedTuple
An immutable (width, height) pair in logical pixels.
A NamedTuple so it is compared by value: two equal sizes are ==,
which lets a size report de-dupe an unchanged measurement without a custom
comparator. It also unpacks like a tuple (w, h = size).
Shadow
dataclass
¶
Shadow(color: ColorSpec, blur_radius: float = 0.0, offset: Tuple[float, float] = (0.0, 0.0), spread_radius: float = 0.0)
A single shadow layer, in CSS box-shadow terms.
A widget's shadow is one or more of these layers, stacked back to front.
Attributes:
| Name | Type | Description |
|---|---|---|
color |
ColorSpec
|
Shadow color. Supports |
blur_radius |
float
|
CSS blur-radius, in pixels. A value of 0.0 means a hard-edged shadow. |
offset |
Tuple[float, float]
|
(dx, dy) translation of the shadow relative to the widget. |
spread_radius |
float
|
CSS spread-radius, in pixels: outward inflation of the shadow rect, applied before the blur. Corner radii grow by the same amount. A negative value shrinks the rect. |
Navigator
¶
Navigator(screen: Widget | None = None, *, transition: TransitionSpec | None = None, layer_composer: NavigationLayerComposer | None = None, key: str | None = None)
Bases: ComposableWidget
A stack of screens; the top one is shown.
Each screen moves with its own transition, given when it enters the stack.
From a list of screens: :meth:routes. From intents and a routing table:
:meth:intents.
Initialize a Navigator with a single initial screen.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
screen
|
Widget | None
|
The initial screen. |
None
|
transition
|
TransitionSpec | None
|
The transition |
None
|
layer_composer
|
NavigationLayerComposer | None
|
Optional custom layer composer. |
None
|
key
|
str | None
|
Stable widget identity for dev-bridge targeting and hot reload. |
None
|
Source code in src/nuiitivet/navigation/navigator.py
stack
property
¶
stack: tuple[Widget, ...]
The screens on the stack, bottom to top.
A popping screen stays until its exit transition ends. To wait for a pop, wait for this to shrink::
navigator.pop()
await app.wait_for(lambda: len(navigator.stack) == 1)
Reading this mounts nothing.
in_transition
property
¶
Whether a navigation is in flight, animated or not.
True from the call to :meth:pop until the stack settles, including
before the pop's task starts. Prefer waiting on :attr:stack when the
depth changes.
routes
classmethod
¶
routes(screens: Sequence[ScreenLike], *, layer_composer: NavigationLayerComposer | None = None) -> Navigator
Create a Navigator that starts with several screens on its stack.
Use this for deep linking or restoring state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
screens
|
Sequence[ScreenLike]
|
Screens bottom to top; the last one is shown. Each is a
widget or a |
required |
layer_composer
|
NavigationLayerComposer | None
|
Optional custom layer composer. |
None
|
Source code in src/nuiitivet/navigation/navigator.py
intents
classmethod
¶
intents(*, initial: Any, routes: Mapping[type[Any], Callable[[Any], ScreenLike]], layer_composer: NavigationLayerComposer | None = None) -> Navigator
Create a Navigator that resolves intents through a routing table.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial
|
Any
|
The intent that resolves the first screen. |
required |
routes
|
Mapping[type[Any], Callable[[Any], ScreenLike]]
|
Mapping of intent types to factories. Each factory returns
a widget or a |
required |
layer_composer
|
NavigationLayerComposer | None
|
Optional custom layer composer. |
None
|
Source code in src/nuiitivet/navigation/navigator.py
of
classmethod
¶
of(context: Widget, root: bool = False) -> NavigatorT
Return the Navigator that navigation from context should drive.
The nearest ancestor wins, so a nested navigator keeps its own history. With no ancestor, the App's navigator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
Widget
|
A widget in the subtree from which to resolve. |
required |
root
|
bool
|
Return the App's navigator, skipping ancestors. Use it for a full-window push from inside a nested navigator. |
False
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
Source code in src/nuiitivet/navigation/navigator.py
push
¶
push(screen: Widget | Any, *, transition: TransitionSpec | None = None) -> None
Push a new screen onto the navigation stack.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
screen
|
Widget | Any
|
A widget, or an intent resolved through the navigator's routes. |
required |
transition
|
TransitionSpec | None
|
The transition the widget moves with, on push and later
on pop. Defaults to none; |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
Source code in src/nuiitivet/navigation/navigator.py
snapshot_stack
¶
Return the restore log for :meth:restore_stack, not the route stack.
One entry per :meth:push, bottom to top: a descriptor for an intent,
None for a widget. The initial screens are left out; a hot reload
rebuilds them from the factory.
Source code in src/nuiitivet/navigation/navigator.py
restore_stack
¶
Replay a restore log onto a freshly built navigator, without animation.
Replay stops at a widget entry or an intent no longer registered; the screens above it are lost.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
descriptors
|
Sequence[_PushDescriptor | None]
|
What :meth: |
required |
Returns:
| Type | Description |
|---|---|
int
|
The number of screens restored. |
Source code in src/nuiitivet/navigation/navigator.py
pop
¶
Request a back navigation. The pop itself runs as a task.
Source code in src/nuiitivet/navigation/navigator.py
request_back
async
¶
Request one back action, as from Esc or a back button.
During a pop transition, the request is queued and the running pop finishes at once. Queued pops run without animation, except the last.
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in src/nuiitivet/navigation/navigator.py
focus_traversal_children
¶
focus_traversal_children() -> list[Widget]
Return only the top screen, so Tab never reaches a covered one.
Covered screens stay mounted to keep their state.
Source code in src/nuiitivet/navigation/navigator.py
NavigatorProtocol
¶
Bases: Protocol
The navigation surface a ViewModel depends on.
Annotate an injected navigator with this protocol so the ViewModel stays independent of the widget tree::
class CartViewModel:
def __init__(self, navigator: NavigatorProtocol) -> None:
self._navigator = navigator
def checkout(self) -> None:
self._navigator.push(OrderCompleteIntent())
:class:~nuiitivet.navigation.navigator.Navigator and
:class:~nuiitivet.material.navigator.MaterialNavigator satisfy it
structurally, and a hand-written fake needs only these three methods --
no widget tree and no App.
push
¶
push(screen: Widget | Any, *, transition: TransitionSpec | None = None) -> None
Push a widget, or an intent, onto the navigation stack.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
screen
|
Widget | Any
|
A widget, or an intent resolved through the navigator's routes. |
required |
transition
|
TransitionSpec | None
|
The transition the widget moves with; widgets only. |
None
|
Source code in src/nuiitivet/navigation/protocols.py
pop
¶
OverlayAware
¶
Bases: Generic[T]
Mixin that lets a widget receive its own :class:OverlayHandle.
When a widget inheriting OverlayAware is displayed through any
:class:Overlay show API (show, dialog, side_sheet, bottom_sheet,
snackbar, loading), the framework injects the created handle
into the widget instance before mounting. The widget (or its ViewModel)
can then close itself via self.overlay_handle.close(value) without
requiring the caller to wire the handle manually.
Type parameter T represents the result type returned from
handle.close(value) / await handle. Note that the return type
of the Overlay show APIs stays OverlayHandle[Any]; only the
widget-side view is typed.
Example
class MyDialog(ComposableWidget, OverlayAware[str]): ... def on_save(self) -> None: ... self.overlay_handle.close("saved") ... result = await overlay.dialog(MyDialog())
overlay_handle
property
¶
Return the handle injected by the overlay framework.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If accessed before the widget is displayed via
an |
OverlayProtocol
¶
Bases: Protocol
The core overlay surface a ViewModel depends on.
Core :class:~nuiitivet.overlay.overlay.Overlay offers no scenario-specific
presentation APIs -- dialog, snackbar, and the sheets live on
:class:~nuiitivet.material.overlay.MaterialOverlay. A ViewModel that only
dismisses overlays can depend on this protocol; one that presents them
should use nuiitivet.material.OverlayProtocol
(:class:~nuiitivet.material.protocols.MaterialOverlayProtocol), which
extends this one.
close
¶
close(value: Any = None, target: Widget | None = None) -> None
Close an overlay entry, optionally with a result value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
Result delivered to the awaiting caller. |
None
|
target
|
Widget | None
|
A widget inside the entry to close. Defaults to the topmost entry. |
None
|
Source code in src/nuiitivet/overlay/protocols.py
CancelToken
¶
Tells a run whether its result is still wanted.
One token per run, created and set by the operator; the run only reads it.
That is the whole difference from the hand-rolled threading.Event this
replaces: there is no clear() to misuse and no way to mistake another
run's flag for your own.
Checking is optional and cooperative -- a superseded run's result is discarded whether or not it ever looks. Python cannot interrupt a thread from outside, so this only helps work with a seam to check at::
def load(query: str, cancel: CancelToken) -> list[Row]:
rows: list[Row] = []
for page in range(PAGE_COUNT):
if cancel.superseded:
return [] # stop paying for an answer nobody wants
rows += fetch(query, page)
return rows
A single blocking call has no such seam, and gains nothing from the token.
Source code in src/nuiitivet/observable/switched.py
Clock
¶
Bases: Protocol
Clock API compatible with pyglet.clock.
Install an implementation with :func:set_clock to control when scheduled
callbacks run — a test that drives a cross-thread observable write or a
debounced observable needs this, since the default fallback clock fires on
a background thread at wall-clock time.
Implementations must identify scheduled callbacks by equality, the rule
pyglet.clock uses: unschedule(obj.method) has to cancel a timer
armed with obj.method, even though each attribute access produces a
distinct bound-method object. Comparing by id() instead silently leaks
timers.
Observable
¶
Bases: _ObservableValue[T]
Descriptor for a per-instance observable that can also be used standalone.
Writes from a thread other than the UI thread are marshalled onto it and
coalesced, so a subscriber may safely touch widgets whichever thread set
the value. Pass dispatch=False for an observable no widget will ever
bind to: notification then stays synchronous on the writing thread, and
every intermediate value is delivered rather than only the latest per tick.
Initialize Observable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
default
|
T
|
Initial value; as a class attribute, the value each instance starts from. |
required |
compare
|
Optional[CompareFunc[T]]
|
|
None
|
dispatch
|
bool
|
Whether a write from another thread is delivered on the UI
thread. |
True
|
Source code in src/nuiitivet/observable/value.py
compute
staticmethod
¶
Create a read-only observable whose value is fn().
It recomputes when an observable that fn read changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fn
|
Callable[[], T]
|
Computes the value from the |
required |
dispatch
|
bool
|
Whether a change from another thread is delivered on
the UI thread. |
True
|
Source code in src/nuiitivet/observable/value.py
Clocks
¶
The runtime's installed clock (read and replace).
get
staticmethod
¶
get() -> Clock
Return the clock currently installed.
Read the clock through this call every time instead of keeping a
reference: the backend installs its own clock during App.run(),
so a saved reference goes stale. Save and restore around a test with
this.
Source code in src/nuiitivet/observable/clocks.py
RemoteError
¶
Bases: Exception
An exception of a server or worker function, carried by its class name and message.
A built-in exception reaches the caller as itself. Any other class reaches it as this one: the class may exist only where the function ran.
Initialize RemoteError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
type_name
|
str
|
The name of the class raised in the function. |
required |
message
|
str
|
That exception's text. |
required |
Source code in src/nuiitivet/remote/function.py
WriteOnlyObservable
¶
Bases: Protocol[T_contra]
What a server function receives for an Observable its caller passed.
Annotate the parameter with it; the caller passes a plain Observable::
@nv.server
def import_file(path: str, progress: nv.WriteOnlyObservable[float]) -> int:
...
progress.value = 0.5
Only assignment works. Reading value raises, and there is nothing to
subscribe to: the function runs where the caller's Observable is not.
The caller's Observable takes the newest value written, on the UI thread;
values written in between may be skipped. A write after the call has
ended or was cancelled is dropped.
FileDropEvent
dataclass
¶
FileDropEvent(paths: tuple[Path, ...], x: float, y: float, local_x: Optional[float] = None, local_y: Optional[float] = None)
OS file paths dropped onto the window, delivered to a widget.
x / y are window coordinates of the drop point (top-left origin,
logical pixels); local_x / local_y are relative to the receiving
widget's top-left and are populated at delivery time.
PointerEvent
dataclass
¶
PointerEvent(id: int, type: PointerEventType, x: float, y: float, pointer_type: PointerType = UNKNOWN, dx: float = 0.0, dy: float = 0.0, scroll_x: float = 0.0, scroll_y: float = 0.0, button: Optional[int] = None, buttons: int = 0, timestamp: float = 0.0, is_primary: bool = True, modifier_keys: int = 0, local_x: float = 0.0, local_y: float = 0.0)
Immutable pointer event payload delivered to widgets.
The runtime builds one with :meth:mouse_event or :meth:scroll_event;
so can a test.
Coordinate semantics
x / y are screen (window) coordinates. local_x / local_y
are relative to the top-left of the widget that receives the event and
are populated at dispatch time; on an event that has not been routed to a
widget they default to the screen coordinates' offset of 0.0.
PointerEventType
¶
Bases: str, Enum
Pointer event actions.
Shortcut
dataclass
¶
A key gesture: one key plus a mask of the modifiers held with it.
From a spec string such as "Accel+Shift+S": :meth:parse.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
str
|
The key name, normalized via :func: |
modifiers |
int
|
A bitmask of |
display
property
¶
Human-readable accelerator label for this gesture, per platform.
macOS uses the compact symbol form in Apple's canonical modifier order
(⌃⌥⇧⌘S); other platforms use the Ctrl+Shift+S form.
MOD_ACCEL renders as its resolved physical modifier (⌘ on macOS,
Ctrl elsewhere), so one :class:Shortcut yields the right label
everywhere — this is what menu items show next to their command.
conflicts_with_text_input
property
¶
Return True if this gesture is one a focused text field would type.
Such a gesture does not fire while a text field holds focus — the field
turns it into a character instead. Alt gestures count as conflicting
on every platform, so they are unavailable there too; see
:func:produces_text for why that cannot be narrowed down safely.
parse
classmethod
¶
Parse a "Accel+Shift+S"-style spec into a :class:Shortcut.
Modifier names are case-insensitive and accept the usual spellings:
Accel/Primary, Ctrl/Control, Alt/Option,
Meta/Cmd/Command/Super/Win, Shift. The last
token is the key. A literal + is written as the final token
("Accel++").
Raises:
| Type | Description |
|---|---|
ValueError
|
If the spec is empty, names an unknown modifier, or carries no key. |
Source code in src/nuiitivet/input/shortcut.py
matches
¶
Return True if a key press of key with modifier_keys is this gesture.
MOD_ACCEL is resolved to the platform's physical modifier here, and
the modifier mask must match exactly — Accel+S does not fire on
Accel+Shift+S.
Source code in src/nuiitivet/input/shortcut.py
ShortcutBinding
dataclass
¶
ShortcutBinding(shortcut: Shortcut, on_trigger: VoidCallback, scope: ShortcutScope = FOREGROUND)
A gesture bound to the callback it triggers, and the scope it is live in.
This is the unit the shortcut dispatch tier stores, kept as a type rather
than a bare callable so richer command semantics (can_execute, menu
binding) can be added without changing every call site.
Attributes:
| Name | Type | Description |
|---|---|---|
shortcut |
Shortcut
|
The gesture that triggers the binding. |
on_trigger |
VoidCallback
|
Called with no arguments when the gesture fires. May be sync or async. |
scope |
ShortcutScope
|
When the binding is live. Defaults to
:attr: |
ShortcutScope
¶
Bases: Enum
When a :class:ShortcutBinding is live.
The members widen: each is a superset of the one before it.
Attributes:
| Name | Type | Description |
|---|---|---|
FOCUS |
Live only while the subtree contains the focused node. Needed only when the same command has several targets on screen at once (a dual-pane file manager, a split-view editor), so nothing but focus can decide which one acts. |
|
FOREGROUND |
Live while the subtree is on the topmost interactable layer — not hidden, not on a covered route, not behind a blocking overlay. The default, and the right answer for almost everything. |
|
MOUNT |
Live while the subtree is in the widget tree at all, displayed or not. How an app-wide command is expressed: bind it on the content root, which stays mounted across navigation. |
FocusSource
¶
Bases: str, Enum
Indicates how a :class:FocusNode acquired focus.
Attributes:
| Name | Type | Description |
|---|---|---|
KEYBOARD |
Focus acquired via keyboard navigation (Tab / Shift-Tab). |
|
POINTER |
Focus acquired via a pointer interaction (click-to-focus). |
Theme
dataclass
¶
Theme(mode: str, extensions: List[ThemeExtension] = list(), name: str = '')
Theme container holding design system extensions.
The Theme class itself is design-agnostic. It holds a list of ThemeExtension objects (like MaterialThemeData, CupertinoThemeData) that define the actual look and feel.
extension
¶
of
staticmethod
¶
Return the current :class:Theme from the nearest :class:AppScope.
Reading registers a dependency. The reader is recorded, and a theme change invalidates it: a composable is rebuilt, a leaf is re-measured and repainted. Nothing subscribes and nothing has to unsubscribe.
Read where the value is consumed. A widget with a build() reads
there; a leaf has no build(), so it reads in paint() or
preferred_size(). Never read in __init__ or on_mount: what is
resolved at mount and kept on a field is never corrected again.
A detached context — a widget deliberately measured outside an App, as
tests and offscreen sizing do — resolves no AppScope and quietly
falls back to the light default rather than raising. Paint code runs this
on every frame, so a raising lookup there would turn a cosmetic problem
into a crash. Under a pull that fallback is self-correcting: the next
read, once the widget is attached, resolves the real theme.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
Any
|
A widget in the subtree from which to search upward. |
required |
Returns:
| Type | Description |
|---|---|
'Theme'
|
The app's current theme, or |
'Theme'
|
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
Source code in src/nuiitivet/theme/theme.py
TypeScale
¶
The 15 baseline Material Design 3 type-scale roles.
Values follow the MD3 2021 baseline type scale
(https://m3.material.io/styles/typography/type-scale-tokens):
(font_size, line_height, weight, tracking).
TypeScaleToken
dataclass
¶
Immutable typographic metrics for a single type-scale role.
From a font size alone, with the line height derived: :meth:from_size.
Attributes:
| Name | Type | Description |
|---|---|---|
font_size |
float
|
Glyph size in px. |
line_height |
float
|
Absolute line height in px (faithful to MD3 tokens, not a multiplier). Only affects multi-line layout. |
weight |
int
|
Font weight (100-900); MD3 roles use 400 (Regular) or 500 (Medium). |
tracking |
float
|
Letter spacing in px; may be negative (e.g. Display Large). |
copy_with
¶
Return a new token with the given fields replaced.
Example
TypeScale.TITLE_MEDIUM.copy_with(weight=700)
from_size
classmethod
¶
from_size(font_size: float, *, line_height: float | None = None, weight: int = 400, tracking: float = 0.0) -> 'TypeScaleToken'
Build a token from a raw size when no semantic role applies.
Intended for config-driven numeric sizes (e.g. a widget's *Style
exposing label_font_size), not for public typography. line_height
defaults to font_size * 1.25 to preserve historical spacing.
Source code in src/nuiitivet/theme/type_scale.py
ThemeManager
¶
ThemeManager(initial: Optional[Theme] = None)
Holds the current Theme and notifies its owner on changes.
Source code in src/nuiitivet/theme/manager.py
generation
property
¶
Count of theme changes so far.
Bumped before :attr:on_change runs, so anything deriving a value from
the theme can tell whether what it holds is still current.
set_theme
¶
set_theme(theme: Theme) -> None
Replace the current theme and notify the owner.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
theme
|
Theme
|
The theme to make current. |
required |
Source code in src/nuiitivet/theme/manager.py
ThemeExtension
¶
Animatable
¶
Animatable(initial_value: float, motion: Optional[Motion] = None)
Bases: ObservableBase[T]
Declarative, retargetable animation value.
Assign to target to retarget motion without reversing.
value is read-only and reflects the current animated value.
Subclasses :class:ObservableBase so it is recognised by the pure-C
isinstance fast path used on the widget construction hot path;
it also structurally satisfies :class:ReadOnlyObservableProtocol.
Initialize float animatable value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_value
|
float
|
Initial float value. |
required |
motion
|
Optional[Motion]
|
Optional motion model. If omitted, target assignment updates immediately. |
None
|
Source code in src/nuiitivet/animation/animatable.py
vector
staticmethod
¶
vector(initial_value: V, converter: VectorConverter[V], motion: Optional[Motion] = None) -> 'Animatable[V]'
Initialize vector-converted animatable value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_value
|
V
|
Initial value. |
required |
converter
|
VectorConverter[V]
|
Value/vector converter. |
required |
motion
|
Optional[Motion]
|
Optional motion model. If omitted, target assignment updates immediately. |
None
|
Source code in src/nuiitivet/animation/animatable.py
snap_to
¶
Immediately set both value and target without animating.
Stops any active motion and resets the resolved value and target to
value. Useful for establishing an initial state before the first
animated transition.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
T
|
New current and target value. |
required |
Source code in src/nuiitivet/animation/animatable.py
set_motion
¶
set_motion(motion: Motion) -> None
Replace the active motion model.
Useful when the same animatable must switch motions depending on
direction (e.g. distinct enter/exit timing). Any in-flight motion
continues from its current value/velocity using the new motion on the
next target assignment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
motion
|
Motion
|
New motion model to drive subsequent retargets. |
required |
Source code in src/nuiitivet/animation/animatable.py
stop
¶
Stop any active motion and keep the current value.
Source code in src/nuiitivet/animation/animatable.py
Motion
¶
Bases: Protocol
Protocol for declarative motion.
Motion specs are responsible for advancing MotionState over time and handling retargeting without pausing.
LinearMotion
¶
Linear time-based motion.
Initialize LinearMotion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
duration
|
float
|
Duration in seconds for a full transition. |
required |
Source code in src/nuiitivet/animation/motion.py
BezierMotion
¶
Bezier time-based motion.
Initialize BezierMotion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x1
|
float
|
Control point 1 x. |
required |
y1
|
float
|
Control point 1 y. |
required |
x2
|
float
|
Control point 2 x. |
required |
y2
|
float
|
Control point 2 y. |
required |
duration
|
float
|
Duration in seconds for a full transition. |
required |
Source code in src/nuiitivet/animation/motion.py
SpringMotion
¶
SpringMotion(stiffness: float, damping: float, mass: float, *, initial_velocity: float | Sequence[float] = 0.0, tolerance: float = 0.001)
Spring-based motion.
The result is frame-rate independent, and a stiff spring stays stable when the frame rate drops.
Initialize SpringMotion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stiffness
|
float
|
Spring stiffness constant. |
required |
damping
|
float
|
Damping coefficient. |
required |
mass
|
float
|
Mass attached to the spring. |
required |
initial_velocity
|
float | Sequence[float]
|
Initial velocity in units per second: one number for every dimension, or one per dimension. |
0.0
|
tolerance
|
float
|
Distance from the target, and speed, at or below which the motion is at rest. |
0.001
|
Source code in src/nuiitivet/animation/motion.py
TransitionDefinition
dataclass
¶
TransitionDefinition(motion: Motion, pattern: TransitionPattern)
Defines a complete transition with motion and pattern.
FadePattern
¶
FadePattern(start_alpha: float = 0.0, end_alpha: float = 1.0, *, start_progress: float = 0.0, end_progress: float = 1.0)
Controls opacity based on progress.
The optional start_progress / end_progress window confines the fade
to a sub-range of the overall progress, holding start_alpha before it and
end_alpha after it. This expresses the MD3 "fade through" timing, where
the outgoing element fades out over the first part of the transition and the
incoming element fades in over the later part, so the two never sit at half
opacity simultaneously. The defaults (0.0 → 1.0) keep a plain linear
fade over the full progress.
Source code in src/nuiitivet/animation/transition_pattern.py
SlidePattern
¶
Controls translation based on progress.
Source code in src/nuiitivet/animation/transition_pattern.py
ScalePattern
¶
ScalePattern(start_scale_x: float = 0.8, start_scale_y: float = 0.8, end_scale_x: float = 1.0, end_scale_y: float = 1.0)
Controls scale based on progress.
Source code in src/nuiitivet/animation/transition_pattern.py
FractionalSlidePattern
¶
FractionalSlidePattern(start_x: float = 0.0, start_y: float = 0.0, end_x: float = 0.0, end_y: float = 0.0)
Controls translation as a fraction of the widget's allocated size.
A value of +1.0 means one full width (for x) or height (for y) offset. This allows sheet transitions to slide in/out by exactly their own size, regardless of the actual pixel dimensions.
Source code in src/nuiitivet/animation/transition_pattern.py
Desktop
¶
Operating-system desktop integration (notifications, ...).
notify
staticmethod
¶
Raise a desktop notification.
Fire-and-forget: returns immediately, never raises, and is safe to call from an event handler or a worker thread alike. Failures are logged once per process instead of surfacing — a notification must never take the app down. Delivery is best-effort: the OS may still suppress it (permissions, focus modes) without an error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
title
|
str
|
Headline of the notification. |
required |
body
|
str
|
Text shown under the title; none when empty. |
''
|
Source code in src/nuiitivet/platform/desktop.py
FileDialog
¶
Native open-file / save-file / open-directory dialogs.
All methods are coroutines: the dialog runs in an OS helper process and is
awaited from a worker thread, so the UI keeps painting while it is open.
In a browser the dialog is the page's file picker, which opens only from
a click or a key press; elsewhere the call raises :class:FileDialogError.
Call them from an async event handler::
class Editor(nv.ComposableWidget):
async def _open(self) -> None:
path = await nv.FileDialog.open_file(file_types=["txt", "md"])
if path is None:
return # cancelled
self.text.value = path.read_text()
Each method returns the selected :class:~pathlib.Path, or None when
the user cancelled. :class:FileDialogError is raised when the dialog
cannot be shown at all (e.g. no zenity/kdialog on Linux).
open_file
async
staticmethod
¶
open_file(*, title: Optional[str] = None, initial_dir: Union[Path, str, None] = None, file_types: Optional[Sequence[str]] = None) -> Optional[Path]
Pick an existing file to open.
In a browser the path is a copy of the file in the page's memory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
title
|
Optional[str]
|
Dialog title; the platform's own when omitted. A browser shows its own. |
None
|
initial_dir
|
Union[Path, str, None]
|
Directory the dialog opens in; a leading |
None
|
file_types
|
Optional[Sequence[str]]
|
Extensions the picker is restricted to, without the
leading dot (e.g. |
None
|
Source code in src/nuiitivet/platform/file_dialog.py
open_files
async
staticmethod
¶
open_files(*, title: Optional[str] = None, initial_dir: Union[Path, str, None] = None, file_types: Optional[Sequence[str]] = None) -> list[Path]
Pick one or more existing files to open.
Cancelling returns an empty list — the dialog cannot return zero selections otherwise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
title
|
Optional[str]
|
Dialog title; the platform's own when omitted. |
None
|
initial_dir
|
Union[Path, str, None]
|
Directory the dialog opens in; a leading |
None
|
file_types
|
Optional[Sequence[str]]
|
Extensions the picker is restricted to, without the
leading dot; |
None
|
Source code in src/nuiitivet/platform/file_dialog.py
save_file
async
staticmethod
¶
save_file(*, title: Optional[str] = None, initial_dir: Union[Path, str, None] = None, default_name: Optional[str] = None, file_types: Optional[Sequence[str]] = None) -> Optional[Path]
Pick a destination path to save to.
The returned path may not exist yet; writing the file is the caller's
job. The native dialog asks for overwrite confirmation where the
platform does so. In a browser nothing is asked: the path is in the
page's memory, and the file written there is downloaded when the
handler that called save_file returns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
title
|
Optional[str]
|
Dialog title; the platform's own when omitted. |
None
|
initial_dir
|
Union[Path, str, None]
|
Directory the dialog opens in; a leading |
None
|
default_name
|
Optional[str]
|
File name the dialog starts with. |
None
|
file_types
|
Optional[Sequence[str]]
|
Extensions the saved name is restricted to, where the
platform's save dialog supports it; the macOS |
None
|
Source code in src/nuiitivet/platform/file_dialog.py
open_directory
async
staticmethod
¶
open_directory(*, title: Optional[str] = None, initial_dir: Union[Path, str, None] = None) -> Optional[Path]
Pick an existing directory.
In a browser the path is a copy of the directory's files in the page's memory, and a directory with no file counts as cancelled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
title
|
Optional[str]
|
Dialog title; the platform's own when omitted. |
None
|
initial_dir
|
Union[Path, str, None]
|
Directory the dialog opens in; a leading |
None
|
Source code in src/nuiitivet/platform/file_dialog.py
FileDialogError
¶
Bases: RuntimeError
A dialog could not be shown (helper missing or helper failed).
Distinct from cancellation: the user cancelling a dialog returns None,
never raises.
TrayIcon
¶
TrayIcon(*, icon: Optional[Union[str, Path]] = None, tooltip: ObservableStr = '', menu: Optional[Sequence[MenuEntry]] = None, on_activate: Optional[VoidCallback] = None, dock_visibility: str = 'always')
A system tray icon: image, tooltip, menu, and an activate callback.
Initialize TrayIcon.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
icon
|
Optional[Union[str, Path]]
|
Path to the icon image file (PNG recommended). On macOS a
filename stem ending in |
None
|
tooltip
|
ObservableStr
|
Hover text; a plain string or an Observable one. |
''
|
menu
|
Optional[Sequence[MenuEntry]]
|
The tray menu as :class: |
None
|
on_activate
|
Optional[VoidCallback]
|
Called when the icon itself is activated the platform's
conventional way. Support varies: on macOS only without a
|
None
|
dock_visibility
|
str
|
macOS Dock presence: |
'always'
|
Source code in src/nuiitivet/platform/tray.py
dock_visibility
property
¶
The macOS Dock policy: "always", "auto", or "never".
installed
property
¶
Whether the icon is actually showing in the system tray.
False until the backend installs it, and again after removal or
when the platform cannot host one (no tray area). Apps
adapt through this — e.g. bind a window's close_action to it, or
exit when a tray they depend on is unavailable.
AppScope
¶
AppScope(app: 'App', child: Widget, *, key: Optional[str] = None)
Bases: Widget
Inherited widget that provides access to the App instance.
Also the theme provider: Theme.of resolves against the nearest one of
these. Theme changes are fanned out by the App itself (which owns the
:class:ThemeManager) to every open window; this scope only serves reads.
Source code in src/nuiitivet/runtime/app.py
app
property
¶
The App this scope belongs to, or None once it has been collected.
The App-scoped half of X.of(context) resolves through here — see
:func:nuiitivet.widgeting.context_lookup.find_app.
ExitPolicy
¶
Bases: Enum
When App.run() returns.
Attributes:
| Name | Type | Description |
|---|---|---|
LAST_WINDOW_CLOSED |
The default — the app exits once no window remains open. |
|
MAIN_WINDOW_CLOSED |
Closing the main window closes every other window and exits, regardless of what else is open. |
|
EXPLICIT |
Only |
OSChrome
dataclass
¶
OS-managed window decoration.
Maps variant directly to pyglet.window.Window.WINDOW_STYLE_*.
Attributes:
| Name | Type | Description |
|---|---|---|
variant |
OSChromeVariant
|
Window style. One of: "default", "dialog", "tool", "borderless", "transparent". |
CustomChrome
dataclass
¶
CustomChrome(header: 'Widget', corner_radius: float = 0.0, border: Optional[Border] = None)
Custom (app-drawn) window decoration.
Always uses a borderless OS window (no OS title bar).
Wraps header in :class:~nuiitivet.runtime.title_bar.WindowDragArea
so the user can drag the window by the header.
Attributes:
| Name | Type | Description |
|---|---|---|
header |
'Widget'
|
Widget rendered as the window's title-bar area. |
corner_radius |
float
|
Corner radius in logical pixels applied by the render layer. Content is clipped to a rounded rectangle; pixels outside the rounded corners are cleared to transparent. Note that true desktop-transparency in the corners requires platform-level window compositing support. |
border |
Optional[Border]
|
Optional border drawn around the window edge inside the rounded-corner boundary. |
Border
dataclass
¶
Border specification for CustomChrome.
Attributes:
| Name | Type | Description |
|---|---|---|
color |
'ColorSpec'
|
Border color (any ColorSpec accepted by the theme system). |
width |
float
|
Border width in logical pixels. |
AppProtocol
¶
Bases: Protocol
The application surface a ViewModel depends on.
Annotate the app a ViewModel receives with this protocol so the ViewModel
stays independent of the runtime. Pass it per method call -- the View's
event handler resolves App.of(context) and hands it over::
class SettingsViewModel:
def apply_dark_mode(self, app: AppProtocol) -> None:
app.set_theme("dark")
App.of(context) returns the running app typed as this protocol, and a
hand-written fake needs only these three methods -- no widget tree and no
event loop.
WindowProtocol
¶
Bases: Protocol
The window surface a ViewModel depends on.
Annotate the window a ViewModel receives with this protocol so it can
command its window -- close it, hide it, resize it -- without holding the
full :class:~nuiitivet.runtime.window.Window. Pass it per method call --
the View's event handler resolves Window.of(context) and hands it
over::
class LauncherViewModel:
def send_to_background(self, window: WindowProtocol) -> None:
window.hide()
Window.of(context) returns an object satisfying it, and a fake needs
only these members. Every method is a no-op when the OS window does not
exist (not realized yet, or already closed).
Window
¶
Window(content: Widget | RootFactory, width: WindowSizingLike = 'auto', height: WindowSizingLike = 'auto', *, title: str | None | ObservableBase[str | None] = None, chrome: OSChrome | CustomChrome | None = _UNSET, background: ColorSpec = SURFACE, overlay: Overlay | Callable[[], Overlay] | None = None, window_position: WindowPositionLike | None = None, resizable: bool = True, accepts_first_mouse: bool = True, menu: MenuBar | None = None, parent: Window | None = None, modal: bool = False, close_action: str | ObservableBase[str] = 'close')
One OS window: its widget tree, services, and lifecycle.
Construction builds a model only — no OS window, no mounted tree.
:meth:open realizes it (and registers it with the running
:class:~nuiitivet.runtime.app.App); :meth:close destroys it. One
object is one window lifetime: a closed Window is finished, and showing
the same content again means constructing a new one. State that must
survive a window lives in app-layer Observables passed into the content.
Initialize the Window model. :meth:open realizes it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
Widget | RootFactory
|
The root content. Accepts either a ready |
required |
width
|
WindowSizingLike
|
Window width specification. |
'auto'
|
height
|
WindowSizingLike
|
Window height specification. |
'auto'
|
title
|
str | None | ObservableBase[str | None]
|
OS window title. Accepts a plain string or an
:class: |
None
|
chrome
|
OSChrome | CustomChrome | None
|
Window decoration. Pass an :class: |
_UNSET
|
background
|
ColorSpec
|
Window background color. |
SURFACE
|
overlay
|
Overlay | Callable[[], Overlay] | None
|
The window's overlay: an |
None
|
window_position
|
WindowPositionLike | None
|
Initial window position. Accepts a 9-point
alignment string (e.g. |
None
|
resizable
|
bool
|
Whether the window can be resized. |
True
|
accepts_first_mouse
|
bool
|
macOS only. When |
True
|
menu
|
MenuBar | None
|
The menu bar model (:class: |
None
|
parent
|
Window | None
|
The parent window, or |
None
|
modal
|
bool
|
Whether this window blocks input to its parent chain
while open (framework modal). Requires |
False
|
close_action
|
str | ObservableBase[str]
|
What the OS close button does: |
'close'
|
Source code in src/nuiitivet/runtime/window.py
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | |
navigator
property
¶
navigator: Navigator
This App's root :class:~nuiitivet.navigation.Navigator.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the App has no content root yet. |
overlay
property
¶
This App's root :class:~nuiitivet.overlay.Overlay.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the App has no content root yet. |
menu
property
writable
¶
menu: MenuBar | None
The registered application menu bar model, or None.
Assigning replaces the model wholesale and rebuilds the rendered bar; item properties (label / enabled / checked) may be Observables and propagate live without replacement.
ime
property
¶
This window's IME geometry (cursor rect and window location).
One instance per window, so two windows never race each other's candidate-window positioning.
app
property
¶
The owning :class:~nuiitivet.runtime.app.App.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the window is not attached to an App (it attaches
at :meth: |
is_open
property
¶
Observable open state: True between :meth:open and :meth:close.
is_visible
property
¶
Whether the window is visible (or will be, once realized).
Hidden is not closed: the object, its widget tree, and its geometry stay alive, and the window still counts for the App's exit policy. On Windows/Linux the taskbar entry follows this by itself.
title
property
¶
The window title's current value, or None if unset.
Resolves the title given at construction: a plain string is returned as
is; an :class:~nuiitivet.observable.protocols.ObservableBase is
unwrapped to its current value. Exposed for dev tooling -- the dev
bridge's status reports it so an agent can confirm which app is
running -- and never raises: an observable whose read fails reports
None rather than propagating.
modifier_keys
property
¶
The keyboard-modifier keys currently held down.
A bitmask of MOD_SHIFT/MOD_CTRL/MOD_ALT/MOD_META. This is
the single authoritative source of "which modifier keys are down",
maintained by the backend on every key press and release and cleared on
window deactivation. It is exposed for framework internals only and must
not be treated as mutable application state.
of
staticmethod
¶
Return the Window whose tree contains context.
The returned object is the same Window the opener holds — there is
no proxy type. A ViewModel should receive it typed as
:class:~nuiitivet.runtime.protocols.WindowProtocol. Valid from
on_mount, not from __init__, like every .of() lookup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
Widget
|
The widget context. |
required |
Returns:
| Type | Description |
|---|---|
Window
|
The owning Window. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If called before |
Source code in src/nuiitivet/runtime/window.py
can_handle_back_event
¶
Return True if a back action would be handled.
This is a non-mutating check used by backends to decide whether to consume the OS/back key or let default handlers run (e.g. ESC-to-exit).
Source code in src/nuiitivet/runtime/window.py
handle_back_event
async
¶
Handle a user back action (e.g. Esc).
Priority: - Overlay: close topmost entry if any - Navigator: pop one route if possible
A back action never reaches past a blocking layer. If the overlay had
nothing left to close but is still painting one -- a dialog already
dismissed and animating out is the case that reaches here -- the event
stops, rather than popping the screen the user can still see behind it.
This is the keyboard half of what Overlay.hit_test does for the
pointer; a pass-through layer (toast, banner) blocks neither.
Source code in src/nuiitivet/runtime/window.py
open
¶
open() -> Window
Realize the window: build and mount the tree, register with the App.
The OS window itself is created by the running backend — immediately
when the loop is already running, or when app.run() starts for
windows opened before it.
Returns:
| Type | Description |
|---|---|
Window
|
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the window is already open, is already closed (one object is one window lifetime), no App exists yet, or the parent window is not open. |
Source code in src/nuiitivet/runtime/window.py
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 | |
close
¶
Destroy the window: unmount the tree and close the OS window.
Closing is one-way — the object is finished afterwards. Children close first, transitively. Closing a window that is not open is a no-op.
Source code in src/nuiitivet/runtime/window.py
hide
¶
Hide the window, keeping the object and its widget tree alive.
The counterpart of :meth:show — the pair a tray-resident app parks
and summons its window with. Before the backend realizes the OS
window this just records the desired state (so a window can start
hidden); hiding a window that is not open is a no-op.
Source code in src/nuiitivet/runtime/window.py
show
¶
Make the window visible and bring it to the front, focused.
Also the "summon" action for an already-visible window: it raises and refocuses. Showing a window that is not open is a no-op (a closed Window is finished — construct a new one).
Source code in src/nuiitivet/runtime/window.py
render_to_png
¶
Render the current UI to a PNG file.
Settles first: an interactive app reaches its final layout over the next
frame or two (see :meth:_settle_pending_size_changes), which a single
render would otherwise never draw.
Source code in src/nuiitivet/runtime/window.py
invalidate
¶
Request that the next frame be redrawn.
This sets an internal dirty flag which the render loop checks to decide whether to re-render the UI.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
immediate
|
bool
|
If True and running in pyglet, bypass FPS throttle for next draw |
False
|
content
|
bool
|
If True (default), mark the widget tree as changed so the next frame re-paints it. Pass False when the tree is unchanged and only what lies over it needs the frame: a surface-loss redraw (window show/activate) or a dev overlay. The renderer then reuses the tree it last painted instead of walking it again. |
True
|
Source code in src/nuiitivet/runtime/window.py
request_focus
¶
request_focus(node: Optional[FocusNode], source: FocusSource = KEYBOARD) -> None
Set focus to the given FocusNode. Pass None to clear focus.
Source code in src/nuiitivet/runtime/window.py
center
¶
Center the window on its screen.
Source code in src/nuiitivet/runtime/window.py
maximize
¶
Maximize the window.
Source code in src/nuiitivet/runtime/window.py
minimize
¶
Minimize the window.
Source code in src/nuiitivet/runtime/window.py
restore
¶
Restore the window from maximized/minimized/full-screen state.
Source code in src/nuiitivet/runtime/window.py
full_screen
¶
Enter full screen mode (no toggle; :meth:restore is the way back).
Source code in src/nuiitivet/runtime/window.py
move_to
¶
Move the window to a specific screen position.
Source code in src/nuiitivet/runtime/window.py
resize
¶
Resize the window.
Source code in src/nuiitivet/runtime/window.py
WindowScope
¶
Bases: Widget
Inherited widget that provides access to the owning :class:Window.
Every window's root is wrapped in one of these (inside the app-wide
AppScope), so Window.of(context) — and the window-scoped fallback
of Overlay.of / Navigator.of — resolves to the window the context
belongs to, never to a process-wide default.
Source code in src/nuiitivet/runtime/window.py
WindowPosition
dataclass
¶
Where the OS window opens on a screen.
From an alignment string: alignment.
Attributes:
| Name | Type | Description |
|---|---|---|
alignment_key |
str
|
A nine-point alignment, the layout system's vocabulary. It places the window's outer frame, title bar included, inside the screen's work area: the part not covered by the taskbar, the menu bar or the dock. |
offset |
Tuple[float, float]
|
Screen pixels added after alignment; $+x$ is right, $+y$ is down. |
screen_index |
int
|
The screen to open on; out-of-range values use the last screen. |
WindowSizing
dataclass
¶
Represents how a window requests its initial size along an axis.
Construct with :meth:fixed or :meth:auto.
fixed
classmethod
¶
Fonts
¶
Application-wide font configuration (default family, bundled fonts).
set_default_family
staticmethod
¶
Set the application-wide default font family.
The family is prioritized over locale-based defaults wherever no
explicit font_family is given.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
family_name
|
Optional[str]
|
Font family to use, or |
required |
Source code in src/nuiitivet/rendering/fonts.py
register
staticmethod
¶
Register a font file under a custom family name.
Call at application startup, before any widget is rendered. Once
registered, the family name can be used wherever a font_family is
accepted (e.g. TextStyle(font_family=...),
Icon(..., font_family=...)). The file is loaded lazily on first
use and cached.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Absolute or relative path to a |
required |
family_name
|
str
|
The name to associate with this font. |
required |
Source code in src/nuiitivet/rendering/fonts.py
RendererError
¶
Bases: RuntimeError
The selected renderer can no longer produce frames.
Raised from the draw loop and propagated out of :meth:App.run, so the
app stops with a traceback instead of running with a blank window. Every
other exception raised while drawing a frame is logged once and the loop
goes on.
allow
¶
allow(pattern: Union[str, Pattern[str]]) -> InputFilter
Keep only the characters that match pattern, dropping the rest.
The pattern is matched against one character at a time, so
allow(r"[A-Za-z ]") yields a field that letters and spaces can be typed
into and nothing else. Use :func:matching for a rule about the text as a
whole.
Source code in src/nuiitivet/widgets/input_filter.py
deny
¶
deny(pattern: Union[str, Pattern[str]]) -> InputFilter
Drop the characters that match pattern, keeping the rest.
The inverse of :func:allow, and the better fit when only a few characters
are unwanted: deny(r"[\s]") for a field that must not contain spaces.
Source code in src/nuiitivet/widgets/input_filter.py
digits_only
¶
digits_only() -> InputFilter
matching
¶
matching(pattern: Union[str, Pattern[str]]) -> InputFilter
Reject an edit unless the resulting text matches pattern in full.
Unlike :func:allow, which filters character by character and always
accepts something, this rejects the keystroke outright when the result
would not match -- the rule it enforces is about the text as a whole, so
there is no partial result to keep. It is what expresses "at most one
decimal point"::
input_filter=matching(r"[0-9]*\.?[0-9]*")
The pattern must accept every string the user has to be able to pass
through on the way to a finished value, including "" if the field is to
be clearable.
Source code in src/nuiitivet/widgets/input_filter.py
max_length
¶
max_length(max_chars: int) -> InputFilter
batch
¶
Context manager for batching Observable updates.
server
¶
Mark a function as one that runs on the server when the app is on the web.
The app awaits it the same way on both targets::
@nv.server
def load_orders(user_id: int) -> list[Order]: ...
orders = await load_orders(42)
On the desktop it runs on a worker thread. Either way it shares nothing
with its caller: arguments and the result are copied, and may only be of
the types that survive a connection -- None, bool, int,
float, str, bytes, datetime, date, an Enum, a
dataclass of these, list[T], tuple[T, ...], dict[str, T] and
T | None. An Enum or dataclass in the signature is defined in a
module the page gets, not in a server-only one.
Two parameter types are not data. WriteOnlyObservable[T] receives an
Observable of the caller for the function to report progress into.
CancelToken, declared with a default and never passed by the caller,
is set when the awaiting task is cancelled.
An exception reaches the caller: a built-in one as itself, any other as
:class:RemoteError.
The function's module reaches the browser like any other, and the
function's body never runs there. A module that must stay on the server
calls :func:~nuiitivet.remote.scope.server_only.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fn
|
Callable[P, R]
|
A plain |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
If fn breaks one of these rules. |
Source code in src/nuiitivet/remote/function.py
server_only
¶
Declare that the calling module never leaves the server.
Call it at the top of a module. In a package's __init__.py it covers
every module and file of the package. The web build leaves what is
declared out of the page; a @server function in it is answered by a
stub with its signature. Database addresses, keys, and an import the
browser cannot do belong here. A @worker function cannot.
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the module is loaded in a browser. |
Source code in src/nuiitivet/remote/scope.py
focusable
¶
focusable(enabled: bool = True, on_focus_change: Optional[FocusChangeCallback] = None, on_key: Optional[Callable[[str, int], bool]] = None, on_key_up: Optional[Callable[[str, int], bool]] = None) -> FocusableModifier
Mark the widget as focusable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enabled
|
bool
|
Whether the widget is focusable. |
True
|
on_focus_change
|
Optional[FocusChangeCallback]
|
Callback invoked when focus state changes. |
None
|
on_key
|
Optional[Callable[[str, int], bool]]
|
Callback invoked as |
None
|
on_key_up
|
Optional[Callable[[str, int], bool]]
|
Callback invoked as |
None
|
Source code in src/nuiitivet/modifiers/focus.py
on_mount
¶
Return a modifier that runs callback when the widget is mounted.
The callback runs right after the widget's :meth:Widget.on_mount hook and
before its children are mounted. Exceptions are logged and contained.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
VoidCallback
|
A no-argument callable. If it is a coroutine function, it is started as a task on mount and cancelled on unmount. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
An |
OnMountModifier
|
class: |
Note
Mount is not "once per logical component". A ComposableWidget
rebuild discards the built subtree and mounts freshly-created widget
instances, so the callback runs again for the new instance. Use it for
work tied to the widget instance's presence in the tree, not for
one-time initialization of a component.
Source code in src/nuiitivet/modifiers/lifecycle.py
on_size_changed
¶
Return a modifier that calls callback with the widget's measured size.
The callback receives a :class:Size - the widget's own (width, height)
after layout, excluding its position. Use it to feed a size into imperative
state: a ViewModel, or a plain Observable a child widget binds to::
class ResponsiveScaffold(ComposableWidget):
def __init__(self) -> None:
super().__init__()
self.expanded = Observable(False)
def _on_size(self, size: Size) -> None:
self.expanded.value = size.width >= 700
def build(self) -> Widget:
rail = NavigationRail(..., expanded=self.expanded)
return Row([rail, card], ...).modifier(on_size_changed(self._on_size))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
SizeCallback
|
A callable taking a :class: |
required |
Returns:
| Name | Type | Description |
|---|---|---|
An |
OnSizeChangedModifier
|
class: |
Note
Fires once with the first measurement, so the callback alone is enough to seed the state it drives. After that it fires only when the measured size actually changed; a widget that is re-laid-out at the same size, or merely moved, is silent.
Note
Dispatched between frames, never during layout, so the callback may safely do anything - push a route, write an Observable, replace children - and its effect lands on the frame after the measurement.
That includes the first call, which therefore arrives after the first paint. Give an Observable the value you expect at the initial size and the first report writes the same value, which de-dupes: no visible transition. Seed it differently and the widget animates once on startup.
Warning
Avoid making the callback change the measured widget's own size: that
feeds back into the next measurement and can oscillate. The structurally
safe pattern is to measure a widget whose size the parent imposes
(Sizing.weight(...) / "wt") and let the callback change only what
is inside it.
Source code in src/nuiitivet/modifiers/size_changed.py
on_unmount
¶
Return a modifier that runs callback when the widget is unmounted.
The callback runs right after the widget's :meth:Widget.on_unmount hook
and before its children are unmounted. Exceptions are logged and contained.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
VoidCallback
|
A no-argument callable. A coroutine function is scheduled as a task, which may outlive the widget — prefer a synchronous callback for cleanup that must complete. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
An |
OnUnmountModifier
|
class: |
Source code in src/nuiitivet/modifiers/lifecycle.py
opacity
¶
Return a modifier that applies opacity to a widget during paint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
OpacityLike
|
Opacity value between 0.0 (transparent) and 1.0 (opaque), or an observable providing opacity. |
required |
Note
Opacity is paint-only. A widget at 0.0 still takes its space and its clicks.
Source code in src/nuiitivet/modifiers/transform.py
rotate
¶
Return a modifier that rotates a widget during paint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
angle
|
AngleLike
|
Rotation angle in degrees, or an observable providing degrees. |
required |
origin
|
OriginLike
|
Rotation origin. Accepts any of the nine-point alignment tokens in canonical hyphen form ("center", "top-left", "top-center", "top-right", "center-left", "center-right", "bottom-left", "bottom-center", "bottom-right"); the underscore form ("top_left") is accepted as an alias. Alternatively an (x, y) tuple in local coords. Defaults to "center". |
'center'
|
Note
Rotation is paint-only. The widget keeps the rect its layout gave it and takes clicks there, not where it is painted.
Source code in src/nuiitivet/modifiers/transform.py
scale
¶
Return a modifier that scales a widget during paint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
factor
|
ScaleLike
|
Scale factor (uniform) or (sx, sy) tuple, or an observable. |
required |
origin
|
OriginLike
|
Scale origin. Accepts any of the nine-point alignment tokens in canonical hyphen form ("center", "top-left", "top-center", "top-right", "center-left", "center-right", "bottom-left", "bottom-center", "bottom-right"); the underscore form ("top_left") is accepted as an alias. Alternatively an (x, y) tuple in local coords. Defaults to "center". |
'center'
|
Note
Scale is paint-only. The widget keeps the rect its layout gave it and takes clicks there, not where it is painted.
Source code in src/nuiitivet/modifiers/transform.py
shadows
¶
Draw a stack of shadow layers behind the widget.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
layers
|
ShadowLike
|
A |
required |
Returns:
| Type | Description |
|---|---|
ShadowModifier
|
The modifier to apply. |
Source code in src/nuiitivet/modifiers/shadow.py
translate
¶
Return a modifier that translates a widget during paint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offset
|
TranslateLike
|
Translation offset as (dx, dy) tuple, or an observable. |
required |
Note
Translation is paint-only. The widget keeps the rect its layout gave it and takes clicks there, not where it is painted.