Widgets
The built-in widgets, each a builder that draws into a Buffer.
Factory for fluent widget builders. Every widget draws with Theme.Current, measures text by display
width (truncating with …), and never throws, whatever the area.
Widget.Table()
.Block(Widget.Block().Title(" Services "))
.Header("Name", "Status", "Version")
.Columns(Constraint.Fill(), Constraint.Length(10), Constraint.Length(12)) // layout constraints
.Rows(services, s => new Row(s.Name, new Line(s.Status, Theme.Current.Success), s.Version))
.State(selection) // SelectionState: scrolled to keep the selection visible
.Focused()
.Draw(buf, area);
| Builder | What it draws |
|---|---|
Block() |
Borders (Borders.All, Top, …), BorderType(BoxStyle), Title/TitleBottom, Padding, Focused. Draw returns the inner rect. |
Paragraph() |
Text with Wrap(WrapMode.None/Word/Char), Alignment, Scroll(n) or State(ScrollState). Paragraph.MeasureLines measures without drawing. |
List() |
Items(list) or Items(list, format) (only visible rows are formatted), State(SelectionState), HighlightSymbol("> "), Title. |
Table() |
Header, Columns(constraints), ColumnSpacing, Rows, State (▲/▼ on SortColumn), HighlightSymbol, Sortable(columns) (a header click calls SelectionState.ToggleSort, and SortChanged tells you to re-sort). 100,000 rows cost the same per frame as 100. |
Scrollbar() |
Vertical/Horizontal, ContentLength, Position, ViewportLength. Hidden when the content fits. |
Gauge() |
Ratio(0..1) with eighth-cell precision and a percentage (or custom) Label. |
Sparkline() |
Data(values) as ▁▂▃▄▅▆▇█, newest at the right; optional Max. |
Canvas() |
Points, lines, rectangles, circles and Printed text in your own coordinates (XBounds, YBounds; y grows up), drawn in Paint(p => ...) with a Marker: braille (2×4 dots per cell), half blocks, blocks or dots. |
Chart() |
A line or scatter plot of Datasets with an XAxis/YAxis (Axis: bounds from the data unless Min/Max are set, Labels or LabelFormat, Title) and a Legend corner. Datasets without a style take Theme.ChartSeries in order. GraphType.Area fills under a line (draw the larger series first; later ones cover earlier ones). An Axis takes LabelCount, a Formatter, Ticks and a Grid behind the data; Axis.Time("HH:mm") and Axis.Duration() label seconds since the epoch (ChartTime.ToValue(time)) or seconds. |
BarChart() |
Bars(new Bar(label, value), ...), vertical (BarWidth, BarGap) or Direction(Direction.Horizontal), in eighths of a cell, with the value in or after each bar; optional Max, ValueFormat. Groups(new BarGroup(label, bars), ...) draws each group's bars side by side (GroupGap between groups), or as one bar with Stacked(); bar i of each group is series i, colored from Theme.ChartSeries and named in a Legend. |
Spinner() |
Frames(SpinnerFrames.Braille/Line/Dots) and a Label. Animates from the app's clock. |
Toasts() |
Queue(toastQueue): up to 3 pop-ups in the top-right corner that expire on their own. |
StatusBar() |
Left and Right text; the right side wins when both don't fit. |
TextField(), CommandLine() |
Single-line input from TextFieldState / CommandLineState, scrolled by display width, with the terminal cursor shown. |
TextArea() |
Multi-line input from TextAreaState: Wrap(WrapMode.Word/Char/None) (word by default; None scrolls sideways), Placeholder, Block, LineNumbers() (a gutter). Scrolls to keep the cursor visible; with a block, a draggable scrollbar on its right border when the text doesn't fit. |
Select() |
A dropdown field from SelectState: the chosen option (or a muted Placeholder) and a ▼. Opening it shows a PopupMenu of the options below the field; with SelectState.Filterable, a dropdown with a filter line, which typing on the field opens. |
TabBar() |
Tabs(...) with TabBarState, scrolled to keep the selected tab visible. |
Tree(state) |
The expanded part of a TreeState<T>'s tree, with ▸/▾ expanders, Indent(n) or Guides() (│ ├─ └─), Format(node => line), HighlightSymbol, Title. See Trees. |
Button(), Checkbox() |
Themed controls. |
Widget.Chart()
.Datasets(
new Dataset("cpu", cpu), // (double X, double Y) points
new Dataset("p99", latency) { Type = GraphType.Scatter, Marker = Marker.Dot })
.XAxis(new Axis { Title = "s", Min = now - 60, Max = now, LabelFormat = "0" })
.YAxis(new Axis { Title = "%" }) // bounds from the data
.Block(Widget.Block().Title(" Load "))
.Draw(buf, area);
Widget.Canvas()
.XBounds(-1, 1).YBounds(-1, 1)
.Paint(p =>
{
p.Circle(0, 0, 0.8, Theme.Current.Info);
p.Line(0, 0, Math.Cos(angle), Math.Sin(angle));
p.Print(-1, 1, "angle");
})
.Draw(buf, area);
In conhost (the classic Windows console), whose fonts lack eighth blocks, braille and rounded corners, widgets switch to half and full blocks, the line spinner and single borders; canvases and charts draw braille as half blocks. Windows Terminal is unaffected.
Spinners and visible toasts make the app tick (every 100 ms and 250 ms) even with WithTickRate(null),
and only while they're drawn. toasts.Push(text, ToastLevel.Error) is thread-safe; each toast shows
for 4 seconds (or the duration you pass) from when it first appears.
Box styles
Widget.Block().BorderType(BoxStyle.Single).Draw(buf, rect); // ┌─┐
Widget.Block().BorderType(BoxStyle.Double).Draw(buf, rect); // ╔═╗
Widget.Block().BorderType(BoxStyle.Rounded).Draw(buf, rect); // ╭─╮
Widget.Block().BorderType(BoxStyle.Heavy).Draw(buf, rect); // ┏━┓