diff --git a/test.c b/test.c index 38dbfc9b..0358f6e3 100644 --- a/test.c +++ b/test.c @@ -17,6 +17,7 @@ static uiMenuItem editMenu[] = { { "Undo", uiMenuItemTypeCommand }, { uiMenuItemSeparator, uiMenuItemTypeSeparator }, { "Check Me", uiMenuItemTypeCheckbox }, + { "A&ccelerator T_est", uiMenuItemTypeCommand }, { uiMenuItemPreferences, uiMenuItemTypeCommand }, { NULL, 0 }, }; diff --git a/windows/GNUmakeinc.mk b/windows/GNUmakeinc.mk index 4985cb2f..1d83c5db 100644 --- a/windows/GNUmakeinc.mk +++ b/windows/GNUmakeinc.mk @@ -8,6 +8,7 @@ OSCFILES = \ init.c \ label.c \ main.c \ + menu.c \ newcontrol.c \ parent.c \ tab.c \ diff --git a/windows/menu.c b/windows/menu.c new file mode 100644 index 00000000..bd5fbb74 --- /dev/null +++ b/windows/menu.c @@ -0,0 +1,92 @@ +// 20 april 2015 +#include "uipriv_windows.h" + +static void appendSeparator(HMENU menu) +{ + if (AppendMenuW(menu, MF_SEPARATOR, 0, NULL) == 0) + logLastError("error appending separator in appendSeparator()"); +} + +static void appendTextItem(HMENU menu, const char *text) +{ + WCHAR *wtext; + + wtext = toUTF16(text); + if (AppendMenuW(menu, MF_STRING, 0, wtext) == 0) + logLastError("error appending menu item in appendTextItem()"); + uiFree(wtext); +} + +static void appendMenuItem(HMENU menu, const uiMenuItem *item) +{ + // TODO see if there are stock items for these three + if (item->Name == uiMenuItemQuit) { + // TODO verify type + appendSeparator(menu); + appendTextItem(menu, "Quit"); + return; + } + if (item->Name == uiMenuItemPreferences) { + // TODO verify type + appendSeparator(menu); + appendTextItem(menu, "Preferences"); + return; + } + if (item->Name == uiMenuItemAbout) { + // TODO verify type + appendSeparator(menu); + appendTextItem(menu, "About"); + return; + } + if (item->Name == uiMenuItemSeparator) { + // TODO verify type + appendSeparator(menu); + return; + } + switch (item->Type) { + case uiMenuItemTypeCommand: + case uiMenuItemTypeCheckbox: + appendTextItem(menu, item->Name); + return; + } + // TODO complain +} + + +static HMENU makeMenu(uiMenuItem *items) +{ + HMENU menu; + const uiMenuItem *i; + + menu = CreatePopupMenu(); + if (menu == NULL) + logLastError("error creating menu in makeMenu()"); + for (i = items; i->Name != NULL; i++) + appendMenuItem(menu, i); + return menu; +} + +HMENU makeMenubar(void) +{ + HMENU menubar; + const uiMenu *m; + WCHAR *wname; + HMENU menu; + + if (options.Menu == NULL) + complain("asked to give uiWindow a menubar but didn't specify a menu in uiInitOptions"); + + menubar = CreateMenu(); + if (menubar == NULL) + logLastError("error creating menubar in makeMenubar()"); + + for (m = options.Menu; m->Name != NULL; m++) { + wname = toUTF16(m->Name); + menu = makeMenu(m->Items); + if (AppendMenuW(menubar, MF_POPUP | MF_STRING, (UINT_PTR) menu, wname) == 0) + logLastError("error appending menu to menubar in makeMenubar()"); + uiFree(wname); + } + + return menubar; +} diff --git a/windows/uipriv_windows.h b/windows/uipriv_windows.h index 1165a865..309f5cfc 100644 --- a/windows/uipriv_windows.h +++ b/windows/uipriv_windows.h @@ -40,34 +40,37 @@ enum { #define HWND(c) ((HWND) uiControlHandle(uiControl(c))) #define uiParentHWND(p) ((HWND) uiParentHandle(p)) -// debug_windows.c +// debug.c extern HRESULT logLastError(const char *); extern HRESULT logHRESULT(const char *, HRESULT); extern HRESULT logMemoryExhausted(const char *); -// init_windows.c +// init.c extern HINSTANCE hInstance; extern int nCmdShow; extern HFONT hMessageFont; extern HBRUSH hollowBrush; -// util_windows.c +// util.c extern int windowClassOf(HWND, ...); -// text_windows.c +// text.c extern WCHAR *toUTF16(const char *); extern char *toUTF8(const WCHAR *); extern WCHAR *windowText(HWND); -// comctl32_windows.c +// comctl32.c extern BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); extern BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR); extern LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM); extern const char *initCommonControls(void); -// window_windows.c +// window.c extern ATOM registerWindowClass(HICON, HCURSOR); -// parent_windows.c +// parent.c extern HWND initialParent; extern const char *initParent(HICON, HCURSOR); + +// menu.c +extern HMENU makeMenubar(void); diff --git a/windows/window.c b/windows/window.c index 181a9f95..90155a2c 100644 --- a/windows/window.c +++ b/windows/window.c @@ -87,6 +87,7 @@ static void windowDestroy(uiWindow *ww) // and finally destroy // TODO check for errors DestroyWindow(w->hwnd); + // no need to explicitly destroy the menubar, if any; that's done automatically during window destruction } static uintptr_t windowHandle(uiWindow *ww) @@ -180,20 +181,27 @@ static void windowSetMargined(uiWindow *ww, int margined) uiParentUpdate(w->content); } -uiWindow *uiNewWindow(const char *title, int width, int height) +uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) { struct window *w; RECT adjust; WCHAR *wtitle; + BOOL hasMenubarBOOL; + HMENU hmenu; w = uiNew(struct window); w->onClosing = defaultOnClosing; + hasMenubarBOOL = FALSE; + if (hasMenubar) + hasMenubarBOOL = TRUE; + adjust.left = 0; adjust.top = 0; adjust.right = width; adjust.bottom = height; - if (AdjustWindowRectEx(&adjust, style, FALSE, exstyle) == 0) + // TODO does not handle menu wrapping; see http://blogs.msdn.com/b/oldnewthing/archive/2003/09/11/54885.aspx + if (AdjustWindowRectEx(&adjust, style, hasMenubarBOOL, exstyle) == 0) logLastError("error getting real window coordinates in uiWindow()"); wtitle = toUTF16(title); @@ -209,6 +217,12 @@ uiWindow *uiNewWindow(const char *title, int width, int height) w->content = uiNewParent((uintptr_t) (w->hwnd)); + if (hasMenubar) { + hmenu = makeMenubar(); + if (SetMenu(w->hwnd, hmenu) == 0) + logLastError("error giving menu to window in uiNewWindow()"); + } + uiWindow(w)->Destroy = windowDestroy; uiWindow(w)->Handle = windowHandle; uiWindow(w)->Title = windowTitle;