DVUI

borderAndBackground

Parameters

#
self:*const WidgetData
*const WidgetData
opts:struct { fill_color: ?Color = null, ninepatch: ?*const Ninepatch = null, }
struct { fill_color: ?Color = null, ninepatch: ?*const Ninepatch = null, }

Source

Implementation

#
pub fn borderAndBackground(self: *const WidgetData, opts: struct {
    fill_color: ?Color = null,
    ninepatch: ?*const Ninepatch = null,
}) void {
    if (!self.visible()) {
        return;
    }

    if (self.options.box_shadow) |bs| {
        const rs = self.borderRectScale();
        const corners = bs.corners orelse self.options.cornersGet();

        const prect = rs.r.insetAll(rs.s * bs.shrink).offsetPoint(bs.offset.scale(rs.s, dvui.Point.Physical));

        prect.fill(corners.scale(rs.s, CornerRect.Physical), .{ .color = bs.color.opacity(bs.alpha), .fade = rs.s * bs.fade });
    }

    var bg = self.options.backgroundGet();
    const b = self.options.borderGet();

    if (b.nonZero()) {
        const uniform: bool = (b.x == b.y and b.x == b.w and b.x == b.h);
        if (uniform) {
            // draw border as stroked path
            const r = self.borderRect().inset(b.scale(0.5, Rect));
            const rs = self.rectScale().rectToRectScale(r.offsetNeg(self.rect));
            rs.r.stroke(self.options.cornersGet().scale(rs.s, CornerRect.Physical), .{ .thickness = b.x * rs.s, .color = self.options.color(.border) });
        } else {
            // non-uniform border, draw it first as large rect with background/ninepatch on top
            if (!bg) {
                dvui.log.debug("borderAndBackground {x} forcing background on to support non-uniform border\n", .{self.id});
                bg = true;
            }

            var rs = self.borderRectScale();
            if (!rs.r.empty()) {
                const fade: f32 = if (dvui.windowNaturalScale() >= 2.0) 0.0 else 1.0;
                if (fade > 0) {
                    // if any border is zero, inset by half the fade so it doesn't bleed out
                    var inset: Rect.Physical = .{};
                    if (b.x == 0) inset.x = fade * 0.5;
                    if (b.y == 0) inset.y = fade * 0.5;
                    if (b.w == 0) inset.w = fade * 0.5;
                    if (b.h == 0) inset.h = fade * 0.5;
                    rs.r = rs.r.inset(inset);
                }
                rs.r.fill(self.options.cornersGet().scale(rs.s, CornerRect.Physical), .{
                    .color = self.options.color(.border),
                    .fade = fade,
                });
            }
        }
    }

    const ninepatch = opts.ninepatch orelse self.options.ninepatch(.fill);

    if (bg) {
        const rs = self.backgroundRectScale();
        if (!rs.r.empty()) {
            const fill = opts.fill_color orelse self.options.color(.fill);
            rs.r.fill(self.options.cornersGet().scale(rs.s, CornerRect.Physical), .{
                .color = fill,
                .fade = if (ninepatch != null or dvui.windowNaturalScale() >= 2.0) 0.0 else 1.0,
            });
        }
    }

    // can draw a ninepatch without a background, some of it could be transparent
    if (ninepatch) |np| {
        const rs = self.backgroundRectScale();
        dvui.renderNinepatch(np.*, rs, .{}) catch |err| {
            dvui.log.err("while drawing ninepatch: {}, {}", .{ err, rs });
        };
    }
}