vxfw: improve .mouse_leave delivery
This commit is contained in:
parent
90eb6489a2
commit
37aeabc647
2 changed files with 84 additions and 6 deletions
73
examples/split_view.zig
Normal file
73
examples/split_view.zig
Normal 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(), .{});
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue