add mouse clipping to hidden boxes from scrolling

This commit is contained in:
Rokas Puzonas 2025-02-07 00:59:45 +02:00
parent d744ab4b6b
commit 401056b676
2 changed files with 37 additions and 8 deletions

View File

@ -198,3 +198,16 @@ pub fn aligned(rect: Rect, align_x: AlignX, align_y: AlignY) rl.Vector2 {
return rl.Vector2.init(x, y);
}
pub fn intersect(rect: Rect, other: Rect) Rect {
const left_pos = @max(left(rect), left(other));
const top_pos = @max(top(rect), top(other));
const right_pos = @min(right(rect), right(other));
const bottom_pos = @min(bottom(rect), bottom(other));
return Rect{
.x = left_pos,
.y = top_pos,
.width = right_pos - left_pos,
.height = bottom_pos - top_pos
};
}

View File

@ -378,6 +378,10 @@ pub const Box = struct {
return self.flags.contains(flag);
}
fn hasClipping(self: *Box) bool {
return self.view_offset.equals(Vec2.zero()) == 0;
}
};
const BoxChildIterator = struct {
@ -627,7 +631,7 @@ pub fn draw(self: *UI) void {
fn drawBox(self: *UI, box: *Box) void {
const box_rect = box.computedRect();
const do_scissor = box.view_offset.equals(Vec2.zero()) == 0;
const do_scissor = box.hasClipping();
if (do_scissor) {
rl.beginScissorMode(
@intFromFloat(box_rect.x),
@ -1004,11 +1008,20 @@ fn findBoxByKey(self: *UI, key: Key) ?*Box {
pub fn signalFromBox(self: *UI, box: *Box) Signal {
var result = Signal{};
var rect = box.computedRect();
{
var parent_iter = self.iterUpwardByParent(box);
while (parent_iter.next()) |parent| {
if (parent.hasClipping()) {
rect = rect_utils.intersect(rect, parent.computedRect());
}
}
}
const key = box.key;
const rect = box.computedRect();
const is_mouse_inside = rect_utils.isInsideVec2(rect, self.mouse);
const clickable = box.flags.contains(.clickable);
const draggable = box.flags.contains(.draggable_x) or box.flags.contains(.draggable_y);
const is_mouse_inside = rect_utils.isInsideVec2(rect, self.mouse);
var event_index: usize = 0;
while (event_index < self.events.len) {
@ -1153,6 +1166,12 @@ pub fn pushScrollbar(self: *UI, key: UI.Key) *Box {
};
self.pushParent(content_area);
const visible_content_size = content_area.persistent.size.y;
const used_content_size = content_area.persistent.children_size.y;
const visible_percent = clamp(visible_content_size / used_content_size, 0, 1);
const sroll_offset = content_area.persistent.sroll_offset;
content_area.view_offset.y = sroll_offset * (1 - visible_percent) * used_content_size;
return content_area;
}
@ -1182,19 +1201,16 @@ pub fn popScrollbar(self: *UI) void {
.y = UI.Size.percent(visible_percent, 1),
};
const sroll_offset = &content_area.persistent.sroll_offset;
const scrollbar_height = scrollbar_area.persistent.size.y;
const max_offset = scrollbar_height * (1 - visible_percent);
draggable.setFixedY(scrollbar_area.persistent.position.y + sroll_offset.* * max_offset);
const sroll_offset = &draggable.persistent.sroll_offset;
const signal = self.signalFromBox(draggable);
if (signal.dragged()) {
sroll_offset.* += signal.drag.y / max_offset;
sroll_offset.* = clamp(sroll_offset.*, 0, 1);
}
draggable.setFixedY(scrollbar_area.persistent.position.y + sroll_offset.* * max_offset);
content_area.view_offset.y = sroll_offset.* * (1 - visible_percent) * used_content_size;
self.popParent(); // pop container
}