Skip to content

Commit 948d5c7

Browse files
authored
Merge pull request #59 from mochalins/master
Added menubar to win32 backend
2 parents 214dbd6 + acb6987 commit 948d5c7

File tree

1 file changed

+70
-1
lines changed

1 file changed

+70
-1
lines changed

src/backends/win32/backend.zig

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const zigwin32 = @import("zigwin32");
1212
const win32 = zigwin32.everything;
1313
const gdi = @import("gdip.zig");
1414
const HWND = win32.HWND;
15+
const HMENU = win32.HMENU;
1516
const HINSTANCE = win32.HINSTANCE;
1617
const RECT = win32.RECT;
1718
const MSG = win32.MSG;
@@ -162,6 +163,9 @@ var defaultWHWND: HWND = undefined;
162163
pub const Window = struct {
163164
hwnd: HWND,
164165
source_dpi: u32 = 96,
166+
root_menu: ?HMENU,
167+
/// List of menu item callbacks, where the index is the menu item ID
168+
menu_item_callbacks: std.ArrayList(?*const fn () void),
165169

166170
const className = _T("capyWClass");
167171
pub usingnamespace Events(Window);
@@ -249,7 +253,13 @@ pub const Window = struct {
249253
}
250254

251255
defaultWHWND = hwnd;
252-
return Window{ .hwnd = hwnd };
256+
return Window{
257+
.hwnd = hwnd,
258+
.root_menu = null,
259+
.menu_item_callbacks = std.ArrayList(?*const fn () void).init(
260+
lib.internal.lasting_allocator,
261+
),
262+
};
253263
}
254264

255265
// TODO: handle the fact that ONLY the root child must forcibly draw a background
@@ -275,6 +285,51 @@ pub const Window = struct {
275285
_ = win32.SetWindowTextW(self.hwnd, utf16);
276286
}
277287

288+
fn initMenu(self: *Window, menu: HMENU, items: []const lib.MenuItem) !void {
289+
for (items) |item| {
290+
if (item.items.len > 0) {
291+
const submenu = win32.CreateMenu().?;
292+
_ = win32.AppendMenuA(
293+
menu,
294+
win32.MENU_ITEM_FLAGS.initFlags(.{ .POPUP = 1 }),
295+
@intFromPtr(submenu),
296+
item.config.label,
297+
);
298+
try initMenu(self, submenu, item.items);
299+
} else {
300+
_ = win32.AppendMenuA(
301+
menu,
302+
win32.MENU_ITEM_FLAGS.initFlags(.{}),
303+
self.menu_item_callbacks.items.len,
304+
item.config.label,
305+
);
306+
try self.menu_item_callbacks.append(item.config.onClick);
307+
}
308+
}
309+
}
310+
311+
fn clearAndFreeMenus(self: *Window) void {
312+
_ = win32.DestroyMenu(self.root_menu);
313+
self.menu_item_callbacks.clearAndFree();
314+
self.root_menu = null;
315+
}
316+
317+
pub fn setMenuBar(self: *Window, bar: lib.MenuBar) void {
318+
// Detach and free current menu (if exists) from window first.
319+
_ = win32.SetMenu(self.hwnd, null);
320+
self.clearAndFreeMenus();
321+
322+
const root_menu = win32.CreateMenu().?;
323+
self.initMenu(root_menu, bar.menus) catch {
324+
// TODO: Handle error in appropriate way
325+
};
326+
if (win32.SetMenu(self.hwnd, root_menu) != 0) {
327+
self.root_menu = root_menu;
328+
} else {
329+
self.menu_item_callbacks.clearAndFree();
330+
}
331+
}
332+
278333
pub fn setSourceDpi(self: *Window, dpi: u32) void {
279334
self.source_dpi = dpi;
280335
}
@@ -341,6 +396,20 @@ pub fn Events(comptime T: type) type {
341396
else => {},
342397
}
343398
}
399+
// For menubar item events, HIWORD(wp) and lp are set to 0.
400+
else if (code == 0) {
401+
const data = getEventUserData(hwnd);
402+
const window_ptr: ?*Window = @ptrCast(@alignCast(data.peerPtr));
403+
const id: u16 = @intCast(wp & 0xFFFF);
404+
405+
if (window_ptr) |window| {
406+
if (id < window.menu_item_callbacks.items.len) {
407+
if (window.menu_item_callbacks.items[id]) |callback| {
408+
callback();
409+
}
410+
}
411+
}
412+
}
344413
},
345414
win32.WM_CTLCOLOREDIT => {
346415
const data = getEventUserData(@as(HWND, @ptrFromInt(@as(usize, @bitCast(lp)))));

0 commit comments

Comments
 (0)