diff --git a/src/rect-utils.zig b/src/rect-utils.zig index 0a8c442..a94f5b4 100644 --- a/src/rect-utils.zig +++ b/src/rect-utils.zig @@ -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 + }; +} \ No newline at end of file diff --git a/src/ui.zig b/src/ui.zig index 907db5b..48fc372 100644 --- a/src/ui.zig +++ b/src/ui.zig @@ -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 } \ No newline at end of file