textFieldWidget
Display slices and/or arrays of u8 and const u8. If a slice, the slice will be assigned to a duplicated copy of the text widget's buffer.
Parameters
- src:std.builtin.SourceLocation
- std.builtin.SourceLocation
- field_name:[]const u8
- []const u8
- field_value_ptr:anytype
- anytype
- opt:TextFieldOptions
- TextFieldOptions
- alignment:*dvui.Alignment
- *dvui.Alignment
- backing:StringBackingType
- StringBackingType
Source
Implementation
pub fn textFieldWidget(
src: std.builtin.SourceLocation,
field_name: []const u8,
field_value_ptr: anytype,
opt: TextFieldOptions,
alignment: *dvui.Alignment,
backing: StringBackingType,
) void {
validateFieldPtrTypeString(null, "textFieldWidget", @TypeOf(field_value_ptr));
if (opt.display == .none) return;
const T = @TypeOf(field_value_ptr.*);
var box = dvui.box(src, .{ .dir = .horizontal }, .{});
defer box.deinit();
const sentinel_terminated = @typeInfo(T).pointer.sentinel_ptr != null;
var read_only = @typeInfo(@TypeOf(field_value_ptr)).pointer.is_const or opt.display != .read_write;
if (opt.display == .read_write and read_only) {
// Note all string arrays are currently treated as read-only, even if they are var.
// It would be possible to support in-place editing, preferably by implementing a new display option.
log.debug("field {s} display option is set to read_write for read_only string or an array. Displaying as read_only.", .{field_name});
} else if (opt.display == .read_write and sentinel_terminated) {
// Sentinel terminated strings cannot be edited.
// Would require keeping 2 string maps, for sentinel vs non-sentinel strings.
log.debug("field {s} display option is set to read_write for sentinel terminated string or an array. Displaying as read_only.", .{field_name});
read_only = true;
}
dvui.label(@src(), "{s}", .{opt.label orelse field_name}, .{ .margin = .{ .y = 4 } });
if (!read_only) {
// If the original string is heap allocated, then add it to the map so it will be freed before a new string
// is allocated.
if (backing == .gpa and opt.heap_allocated and !string_map.contains(field_value_ptr)) {
string_map.put(dvui.currentWindow().gpa, field_value_ptr, field_value_ptr.*) catch |err| {
dvui.logError(@src(), err, "Error adding to struct_ui.string_map. This will leak memory", .{});
};
}
var hbox_aligned = dvui.box(@src(), .{ .dir = .horizontal }, .{ .margin = alignment.margin(box.data().id) });
defer hbox_aligned.deinit();
alignment.record(box.data().id, hbox_aligned.data());
const textbox_width = dvui.themeGet().font_body.sizeM(dvui.TextEntryWidget.defaultMWidth, 1).w;
const text_box = dvui.textEntry(@src(), if (backing == .buffer) .{ .text = .{ .buffer = backing.buffer }, .multiline = opt.multiline } else .{ .multiline = opt.multiline }, .{
.min_size_content = if (opt.multiline) .{ .h = dvui.themeGet().font_body.lineHeight() * 2, .w = textbox_width } else null,
.max_size_content = if (opt.multiline) .{ .h = dvui.themeGet().font_body.lineHeight() * 4, .w = textbox_width } else null,
});
defer text_box.deinit();
if (!text_box.text_changed and !std.mem.eql(u8, text_box.getText(), field_value_ptr.*)) {
text_box.textSet(field_value_ptr.*, false);
}
if (!@typeInfo(@TypeOf(field_value_ptr)).pointer.is_const and !sentinel_terminated) {
if (text_box.text_changed and !std.mem.eql(u8, text_box.getText(), field_value_ptr.*)) {
switch (backing) {
.gpa => {
if (string_map.getEntry(field_value_ptr)) |entry| {
backing.gpa.free(entry.value_ptr.*);
}
// Memory leaks from this line are caused by not calling struct_ui.deinit()
field_value_ptr.* = backing.gpa.dupe(u8, text_box.getText()) catch "";
string_map.put(dvui.currentWindow().gpa, field_value_ptr, field_value_ptr.*) catch |err| {
dvui.logError(@src(), err, "Error adding to struct_ui.string_map. This will leak memory", .{});
};
},
.buffer => {
field_value_ptr.* = text_box.getText();
},
}
}
}
} else {
var hbox_aligned = dvui.box(@src(), .{ .dir = .horizontal }, .{ .margin = alignment.margin(box.data().id) });
defer hbox_aligned.deinit();
alignment.record(box.data().id, hbox_aligned.data());
dvui.label(@src(), "{s}", .{field_value_ptr.*}, .{ .margin = .{ .y = 4 } });
}
}