feat: make text follow touch/pointer

dev
Louis Pearson 2024-02-17 16:29:09 -07:00
parent c3d240358a
commit 1ba884d7b8
2 changed files with 99 additions and 28 deletions

View File

@ -309,6 +309,16 @@ pub const Surface = struct {
);
}
pub fn frame(surface: Surface, callback: u32) !void {
try surface.conn.send(
Request,
surface.id,
.{ .frame = .{
.callback = callback,
} },
);
}
pub fn commit(surface: Surface) !void {
try surface.conn.send(
Request,

View File

@ -114,16 +114,19 @@ pub fn main() !void {
}
}
std.debug.assert(app.state == .run);
const pool = &app.state.run.pool;
const width = app.state.run.width;
const height = app.state.run.height;
{
std.debug.assert(app.state == .run);
const pool = &app.state.run.pool;
const width = app.state.run.width;
const height = app.state.run.height;
// render
const canvas = try pool.getFramebuffer(.{ width, height });
canvas.renderGradient();
try canvas.attach(surface);
try app.callbacks.put(canvas.buffer.id, bufferHandler);
// render
const canvas = try pool.getFramebuffer(.{ width, height });
canvas.renderGradient();
try canvas.attach(surface);
try app.callbacks.put(canvas.buffer.id, bufferHandler);
}
try app.queue_redraw();
while (app.state != .close) {
const header, const body = try conn.recv();
@ -152,6 +155,7 @@ const App = struct {
callbacks: std.AutoHashMap(u32, Callback),
freetype_lib: freetype.Library,
font_face: freetype.Face,
rerender: ?u32 = null,
display: wayland.core.Display,
shm: wayland.core.Shm,
@ -180,6 +184,14 @@ const App = struct {
x: f32,
y: f32,
},
point: ?struct {
x: f32 = 0,
y: f32 = 0,
} = null,
page_offset: struct {
x: f32,
y: f32,
},
},
close,
},
@ -195,6 +207,15 @@ const App = struct {
app.callbacks.deinit();
}
fn queue_redraw(app: *App) !void {
if (app.rerender) |_| return;
const id = app.conn.id_pool.create();
app.rerender = id;
try app.surface.frame(id);
try app.callbacks.put(id, onFrame);
try app.surface.commit();
}
fn close(app: *App) void {
std.debug.assert(app.state == .run);
app.state.run.pool.deinit();
@ -216,6 +237,7 @@ const App = struct {
.pool = try Pool.init(app.ally, app.shm),
.keyboard = init.keyboard.?,
.mouse = .{ .x = 0, .y = 0 },
.page_offset = .{ .x = 0, .y = 0 },
} };
try app.callbacks.put(app.state.run.keyboard.id, keyboardHandler);
@ -499,8 +521,7 @@ const Canvas = struct {
var x: i32 = @intCast(pos[0]);
var y: i32 = @intCast(pos[1]);
while (unicode_iter.nextCodepoint()) |codepoint| {
const glyph_index = face.getCharIndex(codepoint) orelse continue;
try face.loadGlyph(glyph_index, .{ .render = true });
try face.loadChar(codepoint, .{ .render = true });
const glyph = face.glyph();
const bitmap = glyph.bitmap();
canvas.blitFreetypeBitmap(bitmap, .{ @intCast(x + glyph.bitmapLeft()), @intCast(y - glyph.bitmapTop()) }, color);
@ -547,26 +568,32 @@ fn surfaceDesktopHandler(app: *App, header: wayland.Header, body: []const u32) !
switch (event) {
.configure => |conf| {
try app.xdg_surface.ack_configure(conf.serial);
std.debug.assert(app.state == .run);
const pool = &app.state.run.pool;
const width = app.state.run.width;
const height = app.state.run.height;
// render
const canvas = try pool.getFramebuffer(.{ width, height });
canvas.renderGradient();
try canvas.print(app.font_face, "Hello, World!", .{ 10, 60 }, Color.White);
try canvas.attach(app.surface);
try app.callbacks.put(canvas.buffer.id, bufferHandler);
},
}
}
fn touchHandler(app: *App, header: wayland.Header, body: []const u32) !void {
const event = try wayland.deserialize(wayland.core.Touch.Event, header, body);
_ = app;
switch (event) {
.frame => {},
.down => |touch| {
if (touch.id == 0) {
app.state.run.page_offset.x = @floatFromInt(touch.x >> 8);
app.state.run.page_offset.y = @floatFromInt(touch.y >> 8);
} else {
std.log.info("Non-zero touch id: {}", .{touch});
}
try app.queue_redraw();
},
.motion => |touch| {
if (touch.id == 0) {
app.state.run.page_offset.x = @floatFromInt(touch.x >> 8);
app.state.run.page_offset.y = @floatFromInt(touch.y >> 8);
} else {
std.log.info("Non-zero touch id: {}", .{touch});
}
try app.queue_redraw();
},
else => {
std.log.info("touch event: {}", .{event});
},
@ -577,13 +604,15 @@ fn pointerHandler(app: *App, header: wayland.Header, body: []const u32) !void {
const event = try wayland.deserialize(wayland.core.Pointer.Event, header, body);
switch (event) {
.enter => |enter| {
app.state.run.mouse.x = @floatFromInt(enter.surface_x);
app.state.run.mouse.y = @floatFromInt(enter.surface_y);
app.state.run.page_offset.x = @floatFromInt(enter.surface_x >> 8);
app.state.run.page_offset.y = @floatFromInt(enter.surface_y >> 8);
try app.queue_redraw();
},
.leave => |_| {},
.motion => |motion| {
app.state.run.mouse.x = @floatFromInt(motion.surface_x);
app.state.run.mouse.y = @floatFromInt(motion.surface_y);
app.state.run.page_offset.x = @floatFromInt(motion.surface_x >> 8);
app.state.run.page_offset.y = @floatFromInt(motion.surface_y >> 8);
try app.queue_redraw();
},
else => {
std.log.info("pointer event: {}", .{event});
@ -623,3 +652,35 @@ fn bufferHandler(app: *App, header: wayland.Header, body: []const u32) !void {
const pool = &app.state.run.pool;
try pool.freeFramebuffer(header.object_id);
}
fn onFrame(app: *App, header: wayland.Header, body: []const u32) !void {
_, _ = .{ header, body };
app.rerender = null;
std.debug.assert(app.state == .run);
const pool = &app.state.run.pool;
const width = app.state.run.width;
const height = app.state.run.height;
// render
const canvas = try pool.getFramebuffer(.{ width, height });
canvas.renderGradient();
var offsetx: u32 = if (app.state.run.page_offset.x >= 0) @intFromFloat(app.state.run.page_offset.x) else 0;
var offsety: u32 = if (app.state.run.page_offset.y >= 0) @intFromFloat(app.state.run.page_offset.y) else 0;
if (app.state.run.point) |point| {
offsetx -|= @intFromFloat(point.x);
offsety -|= @intFromFloat(point.y);
}
std.log.info("Calculated page offset: {}, {}", .{ offsetx, offsety });
try canvas.print(
app.font_face,
"Hello, World!",
.{
offsetx + 10,
offsety + 60,
},
Color.White,
);
try canvas.attach(app.surface);
try app.callbacks.put(canvas.buffer.id, bufferHandler);
}