Started implementing menus on Windows.

This commit is contained in:
Pietro Gagliardi 2015-04-20 20:26:21 -04:00
parent b7e2905c72
commit f303f066e2
5 changed files with 120 additions and 9 deletions

1
test.c
View File

@ -17,6 +17,7 @@ static uiMenuItem editMenu[] = {
{ "Undo", uiMenuItemTypeCommand },
{ uiMenuItemSeparator, uiMenuItemTypeSeparator },
{ "Check Me", uiMenuItemTypeCheckbox },
{ "A&ccelerator T_est", uiMenuItemTypeCommand },
{ uiMenuItemPreferences, uiMenuItemTypeCommand },
{ NULL, 0 },
};

View File

@ -8,6 +8,7 @@ OSCFILES = \
init.c \
label.c \
main.c \
menu.c \
newcontrol.c \
parent.c \
tab.c \

92
windows/menu.c Normal file
View File

@ -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;
}

View File

@ -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);

View File

@ -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;