+73
examples/split_view.zig
+73
examples/split_view.zig
···
1
+
const std = @import("std");
2
+
const vaxis = @import("vaxis");
3
+
const vxfw = vaxis.vxfw;
4
+
5
+
const Model = struct {
6
+
split: vxfw.SplitView,
7
+
lhs: vxfw.Text,
8
+
rhs: vxfw.Text,
9
+
children: [1]vxfw.SubSurface = undefined,
10
+
11
+
pub fn widget(self: *Model) vxfw.Widget {
12
+
return .{
13
+
.userdata = self,
14
+
.eventHandler = Model.typeErasedEventHandler,
15
+
.drawFn = Model.typeErasedDrawFn,
16
+
};
17
+
}
18
+
19
+
fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {
20
+
const self: *Model = @ptrCast(@alignCast(ptr));
21
+
switch (event) {
22
+
.init => {
23
+
self.split.lhs = self.lhs.widget();
24
+
self.split.rhs = self.rhs.widget();
25
+
},
26
+
.key_press => |key| {
27
+
if (key.matches('c', .{ .ctrl = true })) {
28
+
ctx.quit = true;
29
+
return;
30
+
}
31
+
},
32
+
else => {},
33
+
}
34
+
}
35
+
36
+
fn typeErasedDrawFn(ptr: *anyopaque, ctx: vxfw.DrawContext) std.mem.Allocator.Error!vxfw.Surface {
37
+
const self: *Model = @ptrCast(@alignCast(ptr));
38
+
const surf = try self.split.widget().draw(ctx);
39
+
self.children[0] = .{
40
+
.surface = surf,
41
+
.origin = .{ .row = 0, .col = 0 },
42
+
};
43
+
return .{
44
+
.size = ctx.max.size(),
45
+
.widget = self.widget(),
46
+
.buffer = &.{},
47
+
.children = &self.children,
48
+
};
49
+
}
50
+
};
51
+
52
+
pub fn main() !void {
53
+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
54
+
defer _ = gpa.deinit();
55
+
56
+
const allocator = gpa.allocator();
57
+
58
+
var app = try vxfw.App.init(allocator);
59
+
defer app.deinit();
60
+
61
+
const model = try allocator.create(Model);
62
+
defer allocator.destroy(model);
63
+
model.* = .{
64
+
.lhs = .{ .text = "Left hand side" },
65
+
.rhs = .{ .text = "right hand side" },
66
+
.split = .{ .lhs = undefined, .rhs = undefined, .width = 10 },
67
+
};
68
+
69
+
model.split.lhs = model.lhs.widget();
70
+
model.split.rhs = model.rhs.widget();
71
+
72
+
try app.run(model.widget(), .{});
73
+
}
+11
-6
src/vxfw/App.zig
+11
-6
src/vxfw/App.zig
···
240
240
if (sub.containsPoint(mouse_point)) {
241
241
try last_frame.hitTest(&hits, mouse_point);
242
242
}
243
+
244
+
// See if our new hit test contains our last handler. If it doesn't we'll send a mouse_leave
245
+
// event
246
+
if (self.maybe_last_handler) |last_handler| {
247
+
for (hits.items) |item| {
248
+
if (item.widget.eql(last_handler)) break;
249
+
} else {
250
+
try last_handler.handleEvent(ctx, .mouse_leave);
251
+
try app.handleCommand(&ctx.cmds);
252
+
}
253
+
}
243
254
while (hits.popOrNull()) |item| {
244
255
var m_local = mouse;
245
256
m_local.col = item.local.col;
···
250
261
// If the event wasn't consumed, we keep passing it on
251
262
if (!ctx.consume_event) continue;
252
263
253
-
if (self.maybe_last_handler) |last_mouse_handler| {
254
-
if (!last_mouse_handler.eql(item.widget)) {
255
-
try last_mouse_handler.handleEvent(ctx, .mouse_leave);
256
-
try app.handleCommand(&ctx.cmds);
257
-
}
258
-
}
259
264
self.maybe_last_handler = item.widget;
260
265
return;
261
266
}