parent
b33f85c2f8
commit
431cd4adf7
|
@ -23,3 +23,23 @@ pub inline fn contains(self: Rectangle, pos: Position) bool {
|
||||||
pos.x <= self.pos.x + self.size.width and
|
pos.x <= self.pos.x + self.size.width and
|
||||||
pos.y <= self.pos.y + self.size.height;
|
pos.y <= self.pos.y + self.size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn intersection(self: Rectangle, other: Rectangle) ?Rectangle {
|
||||||
|
const pos1 = Position{
|
||||||
|
.x = @max(self.pos.x, other.pos.x),
|
||||||
|
.y = @max(self.pos.y, other.pos.y),
|
||||||
|
};
|
||||||
|
|
||||||
|
const pos2 = Position{
|
||||||
|
.x = @min(self.pos.x + self.size.width, other.pos.x + other.size.width),
|
||||||
|
.y = @min(self.pos.y + self.size.height, other.pos.y + other.size.height),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (pos1.x < pos2.x and pos1.y < pos2.y) {
|
||||||
|
return .{
|
||||||
|
.pos = pos1,
|
||||||
|
.size = pos2.sub(pos1).size(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
|
@ -38,3 +38,11 @@ pub inline fn sub(self: Size, other: Size) Size {
|
||||||
pub inline fn position(self: Size) Position {
|
pub inline fn position(self: Size) Position {
|
||||||
return .{ .x = self.width, .y = self.height };
|
return .{ .x = self.width, .y = self.height };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Scales this size by a fraction given as a numerator and denominator.
|
||||||
|
pub inline fn scaleFrac(self: Size, numerator: u31, denominator: u31) Size {
|
||||||
|
return .{
|
||||||
|
.width = self.width * numerator / denominator,
|
||||||
|
.height = self.height * numerator / denominator,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ fn Prototype(comptime Self: type) type {
|
||||||
.ptr,
|
.ptr,
|
||||||
"rect",
|
"rect",
|
||||||
anyerror!void,
|
anyerror!void,
|
||||||
.{ rectangle, color },
|
.{ self, rectangle, color },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ fn Prototype(comptime Self: type) type {
|
||||||
.self,
|
.self,
|
||||||
"strokeRect",
|
"strokeRect",
|
||||||
anyerror!void,
|
anyerror!void,
|
||||||
.{ rectangle, line_width, stroke_color, fill_color },
|
.{ self, rectangle, line_width, stroke_color, fill_color },
|
||||||
)) |ret| try ret else {
|
)) |ret| try ret else {
|
||||||
// TODO: draw as 2 rects if fill_color is set
|
// TODO: draw as 2 rects if fill_color is set
|
||||||
const ud_size = Size{
|
const ud_size = Size{
|
||||||
|
@ -135,7 +135,7 @@ fn Prototype(comptime Self: type) type {
|
||||||
.ptr,
|
.ptr,
|
||||||
"texturedRect",
|
"texturedRect",
|
||||||
anyerror!void,
|
anyerror!void,
|
||||||
.{ src, dest, texture },
|
.{ self, src, dest, texture },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +182,13 @@ fn Prototype(comptime Self: type) type {
|
||||||
Color.fromInt(0x00ff00ff),
|
Color.fromInt(0x00ff00ff),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return statspatch.implcall(self, .ptr, "span", anyerror!void, .{ pos, text_span });
|
return statspatch.implcall(
|
||||||
|
self,
|
||||||
|
.ptr,
|
||||||
|
"span",
|
||||||
|
anyerror!void,
|
||||||
|
.{ self, pos, text_span },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the given chunk of text at the given position.
|
/// Draw the given chunk of text at the given position.
|
||||||
|
@ -212,7 +218,7 @@ fn Prototype(comptime Self: type) type {
|
||||||
.ptr,
|
.ptr,
|
||||||
"chunk",
|
"chunk",
|
||||||
anyerror!void,
|
anyerror!void,
|
||||||
.{ pos, text_chunk },
|
.{ self, pos, text_chunk },
|
||||||
)) |ret| try ret else {
|
)) |ret| try ret else {
|
||||||
for (text_chunk.spans.items) |ss| {
|
for (text_chunk.spans.items) |ss| {
|
||||||
try self.span(pos.add(ss.position), ss.span);
|
try self.span(pos.add(ss.position), ss.span);
|
||||||
|
@ -222,4 +228,39 @@ fn Prototype(comptime Self: type) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Painter = statspatch.StatspatchType(Prototype, void, &zenolith.painter_impls);
|
pub const PainterData = struct {
|
||||||
|
/// A stack of stencils to apply to the rendered shapes. This is used to render partial widgets.
|
||||||
|
/// The topmost stencil should be applied by the painter, if present.
|
||||||
|
sstack: std.ArrayList(Rectangle),
|
||||||
|
|
||||||
|
/// Create a new PainterData. Caller must call deinit.
|
||||||
|
pub fn init(alloc: std.mem.Allocator) PainterData {
|
||||||
|
return .{ .sstack = std.ArrayList(Rectangle).init(alloc) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *PainterData) void {
|
||||||
|
self.sstack.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pushes a rectangular stencil onto the stencil stack. This would typically be called by a
|
||||||
|
/// interested in drawing partial children in the Draw treevent handler.
|
||||||
|
pub fn pushStencil(self: *PainterData, rect: Rectangle) !void {
|
||||||
|
try self.sstack.append(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the topmost stencil from the stencil stack. The caller asserts that the stencil
|
||||||
|
/// stack is not empty.
|
||||||
|
pub fn popStencil(self: *PainterData) void {
|
||||||
|
_ = self.sstack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the topmost stencil of the stencil stack or null if it is empty.
|
||||||
|
/// Painter implementations should call this when drawing shapes and perform clipping.
|
||||||
|
pub fn peekStencil(self: PainterData) ?Rectangle {
|
||||||
|
if (self.sstack.items.len == 0)
|
||||||
|
return null;
|
||||||
|
return self.sstack.items[self.sstack.items.len - 1];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Painter = statspatch.StatspatchType(Prototype, PainterData, &zenolith.painter_impls);
|
||||||
|
|
Loading…
Reference in a new issue