draw
Parameters
- self:*TextEntryWidget
- *TextEntryWidget
Source
Implementation
pub fn draw(self: *TextEntryWidget) void {
self.drawBeforeText();
if (self.len == 0) {
if (self.init_opts.placeholder) |placeholder| {
if (self.data().accesskit_node()) |ak_node| {
AccessKit.nodeSetPlaceholderWithLength(ak_node, placeholder.ptr, placeholder.len);
// Create an empty text run for the empty text entry.
dvui.currentWindow().accesskit.text_run_parent = self.data().id;
self.textLayout.textRunCreateEmpty(self.data().id, true);
// prevent textLayout from making a text run for the placeholder text
dvui.currentWindow().accesskit.text_run_parent = null;
}
self.textLayout.addText(placeholder, .{ .color_text = self.textLayout.data().options.color(.text).opacity(0.65) });
}
}
if (dvui.accesskit_enabled) {
// parent text runs to us
dvui.currentWindow().accesskit.text_run_parent = self.data().id;
}
if (self.init_opts.password_char) |pc| {
{
// adjust selection for obfuscation
var count: usize = 0;
var bytes: usize = 0;
var sel = self.textLayout.selection;
var sstart: ?usize = null;
var scursor: ?usize = null;
var send: ?usize = null;
var utf8it = (std.unicode.Utf8View.initUnchecked(self.text[0..self.len])).iterator();
while (utf8it.nextCodepoint()) |codepoint| {
if (sstart == null and sel.start == bytes) sstart = count * pc.len;
if (scursor == null and sel.cursor == bytes) scursor = count * pc.len;
if (send == null and sel.end == bytes) send = count * pc.len;
count += 1;
bytes += std.unicode.utf8CodepointSequenceLength(codepoint) catch unreachable;
} else {
if (sstart == null and sel.start >= bytes) sstart = count * pc.len;
if (scursor == null and sel.cursor >= bytes) scursor = count * pc.len;
if (send == null and sel.end >= bytes) send = count * pc.len;
}
sel.start = sstart.?;
sel.cursor = scursor.?;
sel.end = send.?;
const password_str: ?[]u8 = dvui.currentWindow().lifo().alloc(u8, count * pc.len) catch null;
if (password_str) |pstr| {
defer dvui.currentWindow().lifo().free(pstr);
for (0..count) |i| {
for (0..pc.len) |pci| {
pstr[i * pc.len + pci] = pc[pci];
}
}
self.textLayout.addText(pstr, self.data().options.strip());
} else {
dvui.log.warn("Could not allocate password_str, falling back to one single password_str", .{});
self.textLayout.addText(pc, self.data().options.strip());
}
}
self.textLayout.addTextDone(self.data().options.strip());
{
// reset selection
var count: usize = 0;
var bytes: usize = 0;
var sel = self.textLayout.selection;
var sstart: ?usize = null;
var scursor: ?usize = null;
var send: ?usize = null;
// NOTE: We assume that all text in the area it valid utf8, loop with exit early on invalid utf8
var utf8it = (std.unicode.Utf8View.initUnchecked(self.text[0..self.len])).iterator();
while (utf8it.nextCodepoint()) |codepoint| {
if (sstart == null and sel.start == count * pc.len) sstart = bytes;
if (scursor == null and sel.cursor == count * pc.len) scursor = bytes;
if (send == null and sel.end == count * pc.len) send = bytes;
count += 1;
bytes += std.unicode.utf8CodepointSequenceLength(codepoint) catch unreachable;
} else {
if (sstart == null and sel.start >= count * pc.len) sstart = bytes;
if (scursor == null and sel.cursor >= count * pc.len) scursor = bytes;
if (send == null and sel.end >= count * pc.len) send = bytes;
}
sel.start = sstart.?;
sel.cursor = scursor.?;
sel.end = send.?;
}
self.drawAfterText();
return;
}
// syntax highlighting
if (dvui.useTreeSitter) {
if (self.init_opts.tree_sitter) |ts| {
// parse is lazy
var iter = ts.parse(self.data().id, "parser", self.text[0..self.len]);
defer iter.deinit();
iter.debug = ts.log_captures;
// reparse if needed
if (self.text_changed and !dvui.firstFrame(self.data().id)) {
var edit: ?dvui.c.TSInputEdit = null;
if (self.init_opts.cache_layout) {
edit = @as(dvui.c.TSInputEdit, undefined);
edit.?.start_byte = @intCast(self.text_changed_start);
edit.?.old_end_byte = @intCast(self.text_changed_end);
edit.?.new_end_byte = @intCast(@as(i64, @intCast(self.text_changed_end)) + self.text_changed_added);
edit.?.start_point = .{ .row = 0, .column = 0 };
edit.?.old_end_point = .{ .row = 0, .column = 0 };
edit.?.new_end_point = .{ .row = 0, .column = 0 };
}
iter.reparse(edit);
}
// set the bytes we need matches for
if (self.textLayout.cacheLayoutBytes()) |clb| {
iter.setByteRange(clb.start, clb.end);
}
// do all matches
const normal_opts = self.data().options.strip();
while (iter.next()) |h| {
self.textLayout.addText(h.text, h.opts orelse normal_opts);
}
self.textLayout.addTextDone(normal_opts);
self.drawAfterText();
return;
}
}
// simple text
self.textLayout.addText(self.text[0..self.len], self.data().options.strip());
self.textLayout.addTextDone(self.data().options.strip());
self.drawAfterText();
}