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;
}