///|
/// Scissor rectangle for clipping (pixel coordinates).
pub(all) struct ScissorRect {
x : Int
y : Int
width : Int
height : Int
}
///|
pub fn ScissorRect::new(
x : Int,
y : Int,
width : Int,
height : Int,
) -> ScissorRect {
{ x, y, width, height }
}
///|
pub fn ScissorRect::from_screen(screen_w : Int, screen_h : Int) -> ScissorRect {
{ x: 0, y: 0, width: screen_w, height: screen_h }
}
///|
/// Intersect two scissor rects. Returns None if they don't overlap.
pub fn ScissorRect::intersect(
self : ScissorRect,
other : ScissorRect,
) -> ScissorRect? {
let x0 = Int::max(self.x, other.x)
let y0 = Int::max(self.y, other.y)
let x1 = Int::min(self.x + self.width, other.x + other.width)
let y1 = Int::min(self.y + self.height, other.y + other.height)
if x1 <= x0 || y1 <= y0 {
None
} else {
Some({ x: x0, y: y0, width: x1 - x0, height: y1 - y0 })
}
}
///|
/// Convert to a DstRegion with the given index count.
pub fn ScissorRect::to_dst_region(
self : ScissorRect,
index_count : Int,
) -> @gfx.DstRegion {
@gfx.new_dst_region(self.x, self.y, self.width, self.height, index_count)
}
///|
/// Stack of scissor rects for nested overflow:hidden.
/// Push narrows the clip region, pop restores.
pub struct ScissorStack {
stack : Array[ScissorRect]
}
///|
pub fn ScissorStack::new(screen_w : Int, screen_h : Int) -> ScissorStack {
{ stack: [ScissorRect::from_screen(screen_w, screen_h)] }
}
///|
/// Current active scissor rect.
pub fn ScissorStack::current(self : ScissorStack) -> ScissorRect {
self.stack[self.stack.length() - 1]
}
///|
/// Push a child scissor rect. The effective clip is the intersection
/// of the current clip and the new rect. Returns false if fully clipped.
pub fn ScissorStack::push(self : ScissorStack, rect : ScissorRect) -> Bool {
let current = self.current()
match current.intersect(rect) {
Some(clipped) => {
self.stack.push(clipped)
true
}
None => {
// Push a zero-area rect so pop() still works
self.stack.push({ x: 0, y: 0, width: 0, height: 0 })
false
}
}
}
///|
/// Pop the last pushed scissor rect.
pub fn ScissorStack::pop(self : ScissorStack) -> Unit {
if self.stack.length() > 1 {
let _ = self.stack.pop()
}
}
///|
/// Whether the current scissor rect has any area.
pub fn ScissorStack::is_visible(self : ScissorStack) -> Bool {
let c = self.current()
c.width > 0 && c.height > 0
}
///|
/// Depth of the scissor stack (1 = root screen, >1 = nested clips).
pub fn ScissorStack::depth(self : ScissorStack) -> Int {
self.stack.length()
}