DVUI

nodeCreateReal

Create a new Node for AccessKit Returns null if no accessibility information is required for this widget.

Parameters

#
self:*AccessKit
*AccessKit
wd:*dvui.WidgetData
*dvui.WidgetData
role:Role
Role

Source

Implementation

#
pub fn nodeCreateReal(self: *AccessKit, wd: *dvui.WidgetData, role: Role) ?*Node {
    if (wd.options.role == .none) return null;
    // text runs are created even if not visible.
    if (!wd.visible() and wd.id != dvui.focusedWidgetId() and role != .text_run) return null;
    if (role == .text_run and self.text_run_parent == null) {
        log.debug("skipping ak text run for widget {x}, text_run_parent null", .{wd.id});
        return null;
    }
    const io = dvui.io;
    self.mutex.lockUncancelable(io);
    defer self.mutex.unlock(io);

    switch (self.status) {
        .off => return null,
        .starting => {
            if (wd.isRoot()) {
                self.status = .on;
            } else {
                return null;
            }
        },
        .on => {},
    }

    if (debug_node_tree)
        std.debug.print("Creating Node for {x}:{d} with role {?t} at {s}:{d}\n", .{ wd.id, wd.id, wd.options.role, wd.src.file, wd.src.line });

    const ak_node = nodeNew(role.asU8()) orelse return null;
    wd.ak_node = ak_node;
    const border_rect = dvui.clipGet().intersect(wd.borderRectScale().r);
    nodeSetBounds(ak_node, .{ .x0 = border_rect.x, .y0 = border_rect.y, .x1 = border_rect.bottomRight().x, .y1 = border_rect.bottomRight().y });
    if (debug_node_tree)
        std.debug.print("Bounds for {[id]x}:{[id]d} {{ {[x0]}, {[y0]}, {[x1]}, {[y1]} }}\n", .{ .id = wd.id, .x0 = border_rect.x, .y0 = border_rect.y, .x1 = border_rect.bottomRight().x, .y1 = border_rect.bottomRight().y });

    if (!wd.isRoot()) {
        if (role == .text_run) {
            // if self.text_run_parent is null, we bailed out above
            if (self.nodes.get(self.text_run_parent.?)) |node| {
                nodePushChild(node, wd.id.asU64());
                if (debug_node_tree)
                    std.debug.print("text_run parent node is {x}\n", .{self.text_run_parent.?});
            } else {
                log.debug("text_run_parent node null for widget {x}", .{wd.id});
            }
        } else if (role == .grid_cell and self.grid_cell_row != .zero) {
            if (self.nodes.get(self.grid_cell_row)) |row_node| {
                nodePushChild(row_node, wd.id.asU64());
            }
        } else {
            nodePushChild(nodeParent(wd), wd.id.asU64());
        }
    }

    if (wd.options.label) |label| {
        switch (label) {
            .by_id => |id| {
                nodePushLabelledBy(ak_node, id.asU64());
            },
            .for_id => |id| blk: {
                const for_node = self.nodes.get(id) orelse {
                    log.debug("label.for_id {x} is not a valid acesskit node", .{id});
                    break :blk;
                };
                AccessKit.nodePushLabelledBy(for_node, wd.id.asU64());
            },
            .label_widget => |direction| {
                switch (direction) {
                    .next => {
                        self.node_to_label = wd.id;
                        self.node_waiting_label = true;
                    },
                    .prev => {
                        std.debug.assert(self.nodes.contains(self.prev_label_id));
                        nodePushLabelledBy(ak_node, self.prev_label_id.asU64());
                    },
                }
            },
            .text => |txt| {
                nodeSetLabelWithLength(ak_node, txt.ptr, txt.len);
            },
        }
    }
    if (wd.options.role == .label) {
        if (self.node_waiting_label) {
            if (self.node_to_label == .zero) {
                self.node_waiting_label = false;
            } else {
                // If the labelled node is no longer visible, it will not be found.
                if (self.nodes.get(self.node_to_label)) |for_node| {
                    nodePushLabelledBy(for_node, wd.id.asU64());
                    self.node_waiting_label = false;
                    self.node_to_label = .zero;
                }
            }
        }
        self.prev_label_id = wd.id;
    }

    std.debug.assert(!self.nodes.contains(wd.id));
    const window: *dvui.Window = @alignCast(@fieldParentPtr("accesskit", self));
    self.nodes.put(window.gpa, wd.id, ak_node) catch |err| {
        dvui.logError(@src(), err, "AccessKit: unable to add node", .{});
        nodeFree(ak_node);
        return null;
    };

    return ak_node;
}