vxfw: improve .mouse_leave delivery

This commit is contained in:
Tim Culverhouse 2024-11-03 18:10:19 -06:00
parent 90eb6489a2
commit 37aeabc647
2 changed files with 84 additions and 6 deletions

73
examples/split_view.zig Normal file
View file

@ -0,0 +1,73 @@
const std = @import("std");
const vaxis = @import("vaxis");
const vxfw = vaxis.vxfw;
const Model = struct {
split: vxfw.SplitView,
lhs: vxfw.Text,
rhs: vxfw.Text,
children: [1]vxfw.SubSurface = undefined,
pub fn widget(self: *Model) vxfw.Widget {
return .{
.userdata = self,
.eventHandler = Model.typeErasedEventHandler,
.drawFn = Model.typeErasedDrawFn,
};
}
fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {
const self: *Model = @ptrCast(@alignCast(ptr));
switch (event) {
.init => {
self.split.lhs = self.lhs.widget();
self.split.rhs = self.rhs.widget();
},
.key_press => |key| {
if (key.matches('c', .{ .ctrl = true })) {
ctx.quit = true;
return;
}
},
else => {},
}
}
fn typeErasedDrawFn(ptr: *anyopaque, ctx: vxfw.DrawContext) std.mem.Allocator.Error!vxfw.Surface {
const self: *Model = @ptrCast(@alignCast(ptr));
const surf = try self.split.widget().draw(ctx);
self.children[0] = .{
.surface = surf,
.origin = .{ .row = 0, .col = 0 },
};
return .{
.size = ctx.max.size(),
.widget = self.widget(),
.buffer = &.{},
.children = &self.children,
};
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var app = try vxfw.App.init(allocator);
defer app.deinit();
const model = try allocator.create(Model);
defer allocator.destroy(model);
model.* = .{
.lhs = .{ .text = "Left hand side" },
.rhs = .{ .text = "right hand side" },
.split = .{ .lhs = undefined, .rhs = undefined, .width = 10 },
};
model.split.lhs = model.lhs.widget();
model.split.rhs = model.rhs.widget();
try app.run(model.widget(), .{});
}

View file

@ -240,6 +240,17 @@ const MouseHandler = struct {
if (sub.containsPoint(mouse_point)) {
try last_frame.hitTest(&hits, mouse_point);
}
// See if our new hit test contains our last handler. If it doesn't we'll send a mouse_leave
// event
if (self.maybe_last_handler) |last_handler| {
for (hits.items) |item| {
if (item.widget.eql(last_handler)) break;
} else {
try last_handler.handleEvent(ctx, .mouse_leave);
try app.handleCommand(&ctx.cmds);
}
}
while (hits.popOrNull()) |item| {
var m_local = mouse;
m_local.col = item.local.col;
@ -250,12 +261,6 @@ const MouseHandler = struct {
// If the event wasn't consumed, we keep passing it on
if (!ctx.consume_event) continue;
if (self.maybe_last_handler) |last_mouse_handler| {
if (!last_mouse_handler.eql(item.widget)) {
try last_mouse_handler.handleEvent(ctx, .mouse_leave);
try app.handleCommand(&ctx.cmds);
}
}
self.maybe_last_handler = item.widget;
return;
}