groupBox
A bordered box with a heading, used to group related widgets, also known as a fieldset.
Only valid between Window.beginand Window.end.
Parameters
- src:std.builtin.SourceLocation
- std.builtin.SourceLocation
- label_str:[]const u8
- []const u8
- opts:Options
- Options
Source
Implementation
pub fn groupBox(src: std.builtin.SourceLocation, label_str: []const u8, opts: Options) *BoxWidget {
var options = group_box_defaults.override(.{
.label = .{ .text = label_str },
}).override(opts);
const text_size = options.fontGet().textSize(label_str);
// Offset top margin and padding to account for label
options.margin.?.y += @max(text_size.h / 2 - options.borderGet().y / 2, 0);
options.padding.?.y += @max(text_size.h / 2 - options.borderGet().y / 2, 0);
const b = widgetAlloc(BoxWidget);
b.init(src, .{}, options);
{
const border = options.borderGet();
if (border.x != border.y or border.y != border.w or border.w != border.h) {
options.border = Rect.all(@max(border.x, border.y, border.w, border.h));
b.data().options.border = options.border;
dvui.log.err("groupBox {x} requires uniform borders, border width set to {d}", .{ b.data().id, options.border.?.x });
dvui.Debug.errorOutline(b.data().rectScale().r);
}
}
if (options.backgroundGet()) {
b.drawBackground();
}
const label_padding: Rect = .{ .x = LabelWidget.defaults.paddingGet().x, .w = LabelWidget.defaults.paddingGet().w, .y = 0, .h = 0 };
const label_rect: Rect = .{
.x = 0, // Starts at padding.
.y = -options.paddingGet().y - options.borderGet().y / 2 - text_size.h / 2,
.w = @min(text_size.w + label_padding.x + label_padding.w, b.data().contentRect().w),
.h = text_size.h,
};
if (!label_rect.empty()) {
labelNoFmt(@src(), label_str, .{ .align_x = 0.5, .align_y = 0.5 }, options.strip().override(.{
.rect = label_rect,
.background = options.background,
.corners = options.corners,
.padding = label_padding,
}));
}
// draw the border
if (b.data().visible() and options.borderGet().nonZero()) {
const wd = b.data();
const rs = wd.rectScale().s;
var path: dvui.Path.Builder = .init(dvui.currentWindow().lifo());
defer path.deinit();
const r = wd.borderRectScale().r.insetAll(options.borderGet().x / 2 * rs);
const cr = options.cornersGet().scale(rs, CornerRect.Physical);
const left_x = r.x + (options.paddingGet().x + options.borderGet().x / 2) * rs;
const right_x = @min(
left_x + text_size.scale(rs, Rect.Physical).w + (label_padding.x + label_padding.w) * rs,
wd.contentRectScale().r.x + wd.contentRectScale().r.w,
);
path.addPoint(.{ .x = left_x, .y = r.y }); // left edge of label
const tl = dvui.Point.Physical{ .x = r.x + cr.tl.radius(), .y = r.y + cr.tl.radius() };
path.addArc(tl, cr.tl.radius(), std.math.pi * 1.5, std.math.pi, false);
const bl = dvui.Point.Physical{ .x = r.x + cr.tl.radius(), .y = r.y + r.h - cr.tl.radius() };
path.addArc(bl, cr.tl.radius(), std.math.pi, std.math.pi * 0.5, false);
const br = dvui.Point.Physical{ .x = r.x + r.w - cr.tl.radius(), .y = r.y + r.h - cr.tl.radius() };
path.addArc(br, cr.tl.radius(), std.math.pi * 0.5, 0, false);
const tr = dvui.Point.Physical{ .x = r.x + r.w - cr.tl.radius(), .y = r.y + cr.tl.radius() };
path.addArc(tr, cr.tl.radius(), std.math.pi * 2, std.math.pi * 1.5, false);
path.addPoint(.{ .x = right_x, .y = r.y }); // right edge of label
path.build().stroke(.{ .thickness = options.borderGet().x * rs, .color = dvui.themeGet().border });
}
return b;
}