From 43bff35d2cebc317cb8eed84345eaeb21974cbac Mon Sep 17 00:00:00 2001 From: David Vanderson Date: Thu, 16 Jun 2022 00:53:55 -0400 Subject: [PATCH] mach: mouse cursor support (#352) adds mouse cursor support for standard cursors Co-authored-by: Stephen Gutekanst --- src/Engine.zig | 4 ++++ src/enums.zig | 13 ++++++++++++ src/platform/mach.js | 18 ++++++++++++++++ src/platform/native.zig | 46 +++++++++++++++++++++++++++++++++++++++++ src/platform/wasm.zig | 6 ++++++ 5 files changed, 87 insertions(+) diff --git a/src/Engine.zig b/src/Engine.zig index 5d412536..d6e8e1ac 100644 --- a/src/Engine.zig +++ b/src/Engine.zig @@ -87,6 +87,10 @@ pub fn getWindowSize(engine: *Engine) structs.Size { return engine.internal.getWindowSize(); } +pub fn setMouseCursor(engine: *Engine, cursor: enums.MouseCursor) !void { + try engine.internal.setMouseCursor(cursor); +} + pub fn hasEvent(engine: *Engine) bool { return engine.internal.hasEvent(); } diff --git a/src/enums.zig b/src/enums.zig index 0029d2f6..dfa3f316 100644 --- a/src/enums.zig +++ b/src/enums.zig @@ -20,6 +20,19 @@ pub const VSyncMode = enum { triple, }; +pub const MouseCursor = enum { + arrow, + ibeam, + crosshair, + pointing_hand, + resize_ew, + resize_ns, + resize_nwse, + resize_nesw, + resize_all, + not_allowed, +}; + pub const MouseButton = enum { left, right, diff --git a/src/platform/mach.js b/src/platform/mach.js index 86e2f656..052d4f16 100644 --- a/src/platform/mach.js +++ b/src/platform/mach.js @@ -294,6 +294,24 @@ const mach = { window.dispatchEvent(new Event("mach-close")); }, + machSetMouseCursor(cursor_ptr, len) { + let mach_name = mach.getString(cursor_ptr, len); + + if (mach_name === 'arrow') document.body.style.cursor = 'default'; + else if (mach_name === 'ibeam') document.body.style.cursor = 'text'; + else if (mach_name === 'crosshair') document.body.style.cursor = 'crosshair'; + else if (mach_name === 'pointing_hand') document.body.style.cursor = 'pointer'; + else if (mach_name === 'resize_ew') document.body.style.cursor = 'ew-resize'; + else if (mach_name === 'resize_ns') document.body.style.cursor = 'ns-resize'; + else if (mach_name === 'resize_nwse') document.body.style.cursor = 'nwse-resize'; + else if (mach_name === 'resize_nesw') document.body.style.cursor = 'nesw-resize'; + else if (mach_name === 'resize_all') document.body.style.cursor = 'move'; + else if (mach_name === 'not_allowed') document.body.style.cursor = 'not-allowed'; + else { + console.log("machSetMouseCursor failed for " + mach_name); + } + }, + machSetWaitEvent(timeout) { mach.wait_event_timeout = timeout; }, diff --git a/src/platform/native.zig b/src/platform/native.zig index 61b63235..2a266016 100644 --- a/src/platform/native.zig +++ b/src/platform/native.zig @@ -20,6 +20,10 @@ pub const Platform = struct { last_position: glfw.Window.Pos, wait_event_timeout: f64 = 0.0, + cursors: [@typeInfo(enums.MouseCursor).Enum.fields.len]?glfw.Cursor = undefined, + cursors_tried: [@typeInfo(enums.MouseCursor).Enum.fields.len]bool = + [_]bool{false} ** @typeInfo(enums.MouseCursor).Enum.fields.len, + native_instance: gpu.NativeInstance, const EventQueue = std.TailQueue(structs.Event); @@ -184,6 +188,14 @@ pub const Platform = struct { }; } + pub fn deinit(platform: *Platform) void { + for (platform.cursors) |glfw_cursor| { + if (glfw_cursor) |cur| { + cur.destroy(); + } + } + } + fn pushEvent(platform: *Platform, event: structs.Event) void { const node = platform.allocator.create(EventNode) catch unreachable; node.* = .{ .data = event }; @@ -318,6 +330,39 @@ pub const Platform = struct { return platform.last_window_size; } + pub fn setMouseCursor(platform: *Platform, cursor: enums.MouseCursor) !void { + // Try to create glfw standard cursor, but could fail. In the future + // we hope to provide custom backup images for these. + // See https://github.com/hexops/mach/pull/352 for more info + + const enum_int = @enumToInt(cursor); + const tried = platform.cursors_tried[enum_int]; + if (!tried) { + platform.cursors_tried[enum_int] = true; + platform.cursors[enum_int] = switch (cursor) { + .arrow => glfw.Cursor.createStandard(.arrow) catch null, + .ibeam => glfw.Cursor.createStandard(.ibeam) catch null, + .crosshair => glfw.Cursor.createStandard(.crosshair) catch null, + .pointing_hand => glfw.Cursor.createStandard(.pointing_hand) catch null, + .resize_ew => glfw.Cursor.createStandard(.resize_ew) catch null, + .resize_ns => glfw.Cursor.createStandard(.resize_ns) catch null, + .resize_nwse => glfw.Cursor.createStandard(.resize_nwse) catch null, + .resize_nesw => glfw.Cursor.createStandard(.resize_nesw) catch null, + .resize_all => glfw.Cursor.createStandard(.resize_all) catch null, + .not_allowed => glfw.Cursor.createStandard(.not_allowed) catch null, + }; + } + + if (platform.cursors[enum_int]) |cur| { + try platform.window.setCursor(cur); + } else { + // TODO: In the future we shouldn't hit this because we'll provide backup + // custom cursors. + // See https://github.com/hexops/mach/pull/352 for more info + std.debug.print("mach: setMouseCursor: {s} not yet supported\n", .{cursor}); + } + } + pub fn hasEvent(platform: *Platform) bool { return platform.events.first != null; } @@ -496,6 +541,7 @@ pub fn main() !void { const allocator = gpa.allocator(); var engine = try Engine.init(allocator); + defer engine.internal.deinit(); var app: App = undefined; try app.init(&engine); diff --git a/src/platform/wasm.zig b/src/platform/wasm.zig index fa613660..176a2b60 100644 --- a/src/platform/wasm.zig +++ b/src/platform/wasm.zig @@ -14,6 +14,7 @@ const js = struct { extern fn machCanvasGetWindowHeight(canvas: CanvasId) u32; extern fn machCanvasGetFramebufferWidth(canvas: CanvasId) u32; extern fn machCanvasGetFramebufferHeight(canvas: CanvasId) u32; + extern fn machSetMouseCursor(cursor_name: [*]const u8, len: u32) void; extern fn machEmitCloseEvent() void; extern fn machSetWaitEvent(timeout: f64) void; extern fn machHasEvent() bool; @@ -84,6 +85,11 @@ pub const Platform = struct { return platform.last_window_size; } + pub fn setMouseCursor(_: *Platform, cursor: enums.MouseCursor) !void { + const cursor_name = @tagName(cursor); + js.machSetMouseCursor(cursor_name.ptr, cursor_name.len); + } + fn pollChanges(platform: *Platform) void { const change_type = js.machChangeShift();