Skip to documentation
SLOP

tiny.gui.model

Reference tiny.gui model

Defined in tiny.gui.

API (45)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callstiny.guimodel
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsNo direct callersprivate sourcelib.gui.src.modeltextByteBoundarymodel.TextRunValidatorvalidate
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsmodel.UiImagevalidatemodel.UiImagepixelCount
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersmodel.UiImagepixelCountmodel.UiImagevalidate
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsframeclampScrollprivate sourcelib.gui.src.surface.decodecommandBorderEdgePaintprivate sourcelib.gui.src.surface.decodecommandImagePaintprivate sourcelib.gui.src.surface.decodecommandPaintprivate sourcelib.gui.src.surface.decodecommandScrollprivate sourcelib.gui.src.surface.decodecommandShadowPaintmodelnonNegativeFinite
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsmodelresolvedTextStylemodelvalidTextPointSizemodelnormalizedTextPointSize
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callswidgethitTestActivatablewidgethitTestIndexmodelpointInRect
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsmodelvalidateTextmodelnormalizedTextPointSizemodelresolvedTextStyle
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsmodelvalidateTextmodeltextGraphemeBoundary
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallsNo direct callsmodelvalidateTextmodeltextStylesEqual
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsmodelnormalizedTextPointSizemodelvalidateTextmodelvalidTextPointSize
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.gui.src.modeltest: metric text runs require valid ...modelresolvedTextStylemodeltextGraphemeBoundarymodeltextStylesEqualmodelvalidTextPointSizemodelvalidateTextRunsmodelvalidateText
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.gui.src.modeltest: text runs require ordered nonem...modelvalidateTextmodelvalidateTextRuns
Static calls · unresolved targets: 0 · external targets: 1.

Source: lib/gui/src/model.zig

zig
const std = @import("std");const filigree = @import("filigree");const flex_layout = @import("arrange");pub const WidgetKind = enum(u8) {    container,    label,    button,    text_input,};pub const ui_state_selected: u64 = 1 << 0;pub const ui_state_disabled: u64 = 1 << 1;pub const ui_state_expanded: u64 = 1 << 2;pub const ui_state_checked: u64 = 1 << 3;pub const ui_state_default: u64 = 1 << 4;pub const ui_state_danger: u64 = 1 << 5;pub const UiOverflow = enum(u8) {    visible,    clip,};pub const UiColor = struct {    r: u8 = 0,    g: u8 = 0,    b: u8 = 0,    a: u8 = 255,};pub const UiPoint = struct {    x: f32 = 0,    y: f32 = 0,};pub const UiLinearGradient = struct {    start: UiPoint = .{},    end: UiPoint = .{ .x = 1 },    start_color: UiColor = .{},    end_color: UiColor = .{},};pub const UiPaint = struct {    background: ?UiColor = null,    linear_gradient: ?UiLinearGradient = null,    foreground: ?UiColor = null,    border: ?UiColor = null,    border_width: f32 = 0,    corner_roundness: f32 = 0,    border_edges: UiBorderPaint = .{},    shadow: UiShadowPaint = .{},    image: ?UiImagePaint = null,};pub const UiImagePaint = struct {    index: u32,    source: flex_layout.Rect = .{},    tint: ?UiColor = null,    opacity: u8 = 255,};pub const UiImage = struct {    width: u32,    height: u32,    pixels: []const u32,    pub fn pixelCount(self: UiImage) usize {        return @as(usize, self.width) * @as(usize, self.height);    }    pub fn validate(self: UiImage) !void {        if (self.width == 0 or self.height == 0) return error.InvalidImage;        if (self.pixels.len < self.pixelCount()) return error.BufferTooSmall;    }};pub const UiImageSet = struct {    images: []const UiImage = &.{},};pub const UiBorderEdgePaint = struct {    color: ?UiColor = null,    width: f32 = 0,};pub const UiBorderPaint = struct {    top: UiBorderEdgePaint = .{},    right: UiBorderEdgePaint = .{},    bottom: UiBorderEdgePaint = .{},    left: UiBorderEdgePaint = .{},};pub const UiShadowPaint = struct {    color: ?UiColor = null,    offset_x: f32 = 0,    offset_y: f32 = 0,    blur_radius: f32 = 0,    spread: f32 = 0,};pub const UiScroll = struct {    overflow_x: UiOverflow = .visible,    overflow_y: UiOverflow = .visible,    scroll_x: f32 = 0,    scroll_y: f32 = 0,};pub fn nonNegativeFinite(value: f32) f32 {    if (!std.math.isFinite(value) or value <= 0) return 0;    return value;}pub const UiTextStyle = struct {    font_asset_id: u64 = 0,    point_size: f64 = 16.0,};pub const UiTextRun = struct {    byte_start: usize,    byte_end: usize,    style_slot: u16 = 0,    foreground: ?UiColor = null,    background: ?UiColor = null,    underline: bool = false,    strikethrough: bool = false,};pub const UiText = struct {    content: []const u8,    runs: []const UiTextRun = &.{},    styles: []const UiTextStyle = &.{},    font_asset_id: u64 = 0,    font_weight: u16 = ui_font_weight_normal,    point_size: f64 = 16.0,    line_height: f64 = 1.2,    wrap_width: f64 = 0.0,    horizontal_align: UiTextAlign = .start,    vertical_align: UiTextAlign = .start,};pub const UiTextAlign = enum(u8) {    start,    center,    end,};pub const UiTextSelection = struct {    cursor_visible: bool = false,    cursor_block: bool = false,    cursor_byte_offset: usize = 0,    selection_active: bool = false,    selection_anchor_byte_offset: usize = 0,    selection_focus_byte_offset: usize = 0,};pub const ui_font_weight_normal: u16 = 400;pub const ui_font_weight_min: u16 = 100;pub const ui_font_weight_max: u16 = 900;pub const TextRunValidator = struct {    previous_end: usize = 0,    pub fn validate(        self: *TextRunValidator,        content: []const u8,        byte_start: usize,        byte_end: usize,    ) error{InvalidTextRun}!void {        if (byte_start < self.previous_end or byte_start >= byte_end) return error.InvalidTextRun;        if (byte_end > content.len) return error.InvalidTextRun;        if (!textByteBoundary(content, byte_start) or !textByteBoundary(content, byte_end)) return error.InvalidTextRun;        self.previous_end = byte_end;    }};pub fn validateTextRuns(content: []const u8, runs: []const UiTextRun) error{InvalidTextRun}!void {    var validator = TextRunValidator{};    for (runs) |run| {        try validator.validate(content, run.byte_start, run.byte_end);    }}pub fn validateText(text: UiText) error{InvalidTextRun}!void {    if (text.styles.len > std.math.maxInt(u16)) return error.InvalidTextRun;    for (text.styles) |style| {        if (!validTextPointSize(style.point_size)) return error.InvalidTextRun;    }    try validateTextRuns(text.content, text.runs);    for (text.runs, 0..) |run, index| {        if (run.style_slot > text.styles.len) return error.InvalidTextRun;        const style = resolvedTextStyle(text, run.style_slot);        const before = if (index > 0 and text.runs[index - 1].byte_end == run.byte_start)            resolvedTextStyle(text, text.runs[index - 1].style_slot)        else            resolvedTextStyle(text, 0);        const after = if (index + 1 < text.runs.len and text.runs[index + 1].byte_start == run.byte_end)            resolvedTextStyle(text, text.runs[index + 1].style_slot)        else            resolvedTextStyle(text, 0);        if (!textStylesEqual(before, style) and            !textGraphemeBoundary(text.content, run.byte_start))        {            return error.InvalidTextRun;        }        if (!textStylesEqual(style, after) and            !textGraphemeBoundary(text.content, run.byte_end))        {            return error.InvalidTextRun;        }    }}pub fn resolvedTextStyle(text: UiText, style_slot: u16) UiTextStyle {    if (style_slot == 0 or style_slot > text.styles.len) {        return .{            .font_asset_id = text.font_asset_id,            .point_size = normalizedTextPointSize(text.point_size),        };    }    return text.styles[style_slot - 1];}pub fn textStylesEqual(left: UiTextStyle, right: UiTextStyle) bool {    return left.font_asset_id == right.font_asset_id and        @as(u64, @bitCast(left.point_size)) == @as(u64, @bitCast(right.point_size));}pub fn normalizedTextPointSize(value: f64) f64 {    return if (validTextPointSize(value)) value else 16.0;}pub fn validTextPointSize(value: f64) bool {    return std.math.isFinite(value) and value > 0;}pub fn textGraphemeBoundary(content: []const u8, index: usize) bool {    if (index == 0 or index == content.len) return true;    if (index > content.len) return false;    var iterator = filigree.unicode.SourceIterator.init(.{ .utf8 = content }, 0) catch return false;    var state: filigree.unicode.GraphemeState = .{};    while (iterator.next() catch return false) |scalar| {        const boundary = !state.consume(scalar.codepoint);        const offset: usize = @intCast(scalar.source.start);        if (offset == index) return boundary;        if (offset > index) return false;    }    return false;}fn textByteBoundary(content: []const u8, index: usize) bool {    if (index == 0 or index == content.len) return true;    return content[index] & 0b1100_0000 != 0b1000_0000;}pub const UiNode = struct {    widget_id: u64,    kind: WidgetKind = .container,    style: flex_layout.Style = .{},    size: flex_layout.Dimensions = .{},    paint: UiPaint = .{},    scroll: UiScroll = .{},    focusable: bool = false,    layer: u8 = 0,    text: ?UiText = null,    text_selection: UiTextSelection = .{},    action: []const u8 = &.{},    role: []const u8 = &.{},    state_flags: u64 = 0,    children: []const UiNode = &.{},};pub const UiSurfaceTree = struct {    available_size: flex_layout.Size,    root: UiNode,};pub const RootFrame = struct {    root_id: u64,    surface_revision: u64,    rect: flex_layout.Rect,    widget_start: usize,    widget_count: usize,};pub const WidgetFrame = struct {    root_id: u64,    widget_id: u64,    kind: WidgetKind,    rect: flex_layout.Rect,    visible_rect: flex_layout.Rect,    paint: UiPaint,    scroll: UiScroll,    constraints: flex_layout.Constraints,    content_size: flex_layout.Size,    focusable: bool,    layer: u8 = 0,    hovered: bool = false,    captured: bool = false,    focused: bool = false,    has_text: bool = false,    action: []const u8 = &.{},    role: []const u8 = &.{},    state_flags: u64 = 0,    text_ref: u64 = 0,    text: ?UiText = null,    text_selection: UiTextSelection = .{},    subtree_size: usize = 1,};pub const UiFrame = struct {    revision: u64 = 0,    root_count: usize = 0,    roots: []const RootFrame = &.{},    widget_count: usize = 0,    widgets: []const WidgetFrame = &.{},    text_layout_revision: u64 = 0,    text_layout_ptr: ?*anyopaque = null,};pub fn pointInRect(rect: flex_layout.Rect, x: f32, y: f32) bool {    return x >= rect.x and y >= rect.y and x <= rect.x + rect.width and y <= rect.y + rect.height;}test "text runs require ordered nonempty UTF-8 byte ranges" {    const content = "a\u{00e9}z";    const valid = [_]UiTextRun{        .{ .byte_start = 0, .byte_end = 1 },        .{ .byte_start = 1, .byte_end = 3 },        .{ .byte_start = 3, .byte_end = 4 },    };    try validateTextRuns(content, &valid);    try std.testing.expectError(error.InvalidTextRun, validateTextRuns(content, &.{        .{ .byte_start = 1, .byte_end = 1 },    }));    try std.testing.expectError(error.InvalidTextRun, validateTextRuns(content, &.{        .{ .byte_start = 1, .byte_end = 2 },    }));    try std.testing.expectError(error.InvalidTextRun, validateTextRuns(content, &.{        .{ .byte_start = 0, .byte_end = 3 },        .{ .byte_start = 2, .byte_end = 4 },    }));    try std.testing.expectError(error.InvalidTextRun, validateTextRuns(content, &.{        .{ .byte_start = 3, .byte_end = 5 },    }));}test "metric text runs require valid slots and grapheme boundaries" {    const content = "a\u{0301}b";    const styles = [_]UiTextStyle{        .{ .font_asset_id = 7, .point_size = 18 },        .{ .point_size = 16 },    };    try validateText(.{        .content = content,        .styles = &styles,        .runs = &.{            .{ .byte_start = 0, .byte_end = 3, .style_slot = 1 },            .{ .byte_start = 3, .byte_end = 4, .style_slot = 2 },        },    });    try validateText(.{        .content = content,        .styles = &styles,        .runs = &.{            .{ .byte_start = 0, .byte_end = 1, .style_slot = 1 },            .{ .byte_start = 1, .byte_end = 3, .style_slot = 1 },        },    });    try std.testing.expectError(error.InvalidTextRun, validateText(.{        .content = content,        .styles = &styles,        .runs = &.{            .{ .byte_start = 0, .byte_end = 1, .style_slot = 1 },            .{ .byte_start = 1, .byte_end = 3, .style_slot = 2 },        },    }));    try std.testing.expectError(error.InvalidTextRun, validateText(.{        .content = content,        .styles = &styles,        .runs = &.{            .{ .byte_start = 1, .byte_end = 3, .style_slot = 1 },        },    }));    try std.testing.expectError(error.InvalidTextRun, validateText(.{        .content = content,        .styles = &styles,        .runs = &.{            .{ .byte_start = 0, .byte_end = 3, .style_slot = 3 },        },    }));    try std.testing.expectError(error.InvalidTextRun, validateText(.{        .content = content,        .styles = &.{.{ .point_size = std.math.nan(f64) }},    }));}

Source: lib/gui/src/root.zig:13

zig
pub const model = @import("model.zig");

Audit

Definitions46
Public names48
Members127
Version26.7.0
Revisiondaab053ee433