#include "osmenu_win.inl"
#include "osgui_win.inl"
#include "osmenuitem_win.inl"
#include "oswindow_win.inl"
#include "../osmenu.h"
#include <core/arrpt.h>
#include <core/heap.h>
#include <sewer/cassert.h>
#include <sewer/ptr.h>
#if !defined(__WINDOWS__)
#error This file is only for Windows
#endif
struct _osmenu_t
{
HMENU hmenu;
bool_t is_popup;
OSWindow *window;
OSMenuItem *parent;
ArrPt(OSMenuItem) *items;
};
OSMenu *osmenu_create(const uint32_t flags)
{
OSMenu *menu = heap_new0(OSMenu);
menu->items = arrpt_create(OSMenuItem);
unref(flags);
return menu;
}
void osmenu_destroy(OSMenu **menu)
{
cassert_no_null(menu);
cassert_no_null(*menu);
cassert((*menu)->parent == NULL);
if ((*menu)->hmenu != NULL)
{
BOOL ok = FALSE;
cassert(GetMenuItemCount((*menu)->hmenu) == 0);
ok = EndMenu();
cassert(ok != 0);
ok = DestroyMenu((*menu)->hmenu);
cassert_unref(ok != 0, ok);
}
cassert(arrpt_size((*menu)->items, OSMenuItem) == 0);
arrpt_destroy(&(*menu)->items, NULL, OSMenuItem);
heap_delete(menu, OSMenu);
}
void osmenu_insert_item(OSMenu *menu, const uint32_t pos, OSMenuItem *item)
{
cassert_no_null(menu);
arrpt_insert(menu->items, pos, item, OSMenuItem);
_osmenu_hmenu_recompute(menu);
}
void osmenu_delete_item(OSMenu *menu, OSMenuItem *item)
{
uint32_t pos = UINT32_MAX;
cassert_no_null(menu);
_osmenuitem_unset_parent(item, menu);
pos = arrpt_find(menu->items, item, OSMenuItem);
arrpt_delete(menu->items, pos, NULL, OSMenuItem);
_osmenu_hmenu_recompute(menu);
}
static void i_remove_all_items(OSMenu *menu)
{
cassert_no_null(menu);
cassert_no_null(menu->hmenu);
arrpt_foreach(item, menu->items, OSMenuItem)
_osmenuitem_unset_parent(item, menu);
arrpt_end()
{
int i, n = GetMenuItemCount(menu->hmenu);
for (i = 0; i < n; ++i)
{
BOOL ok = RemoveMenu(menu->hmenu, 0, MF_BYPOSITION);
cassert_unref(ok == TRUE, ok);
}
cassert(GetMenuItemCount(menu->hmenu) == 0);
}
}
static void i_add_all_items(OSMenu *menu)
{
cassert_no_null(menu);
cassert_no_null(menu->hmenu);
arrpt_foreach(item, menu->items, OSMenuItem)
_osmenuitem_append_to_hmenu(item, menu);
arrpt_end()
}
void osmenu_launch(OSMenu *menu, OSWindow *window, const real32_t x, const real32_t y)
{
cassert_no_null(menu);
cassert(menu->window == NULL);
if (menu->hmenu != NULL && menu->is_popup == FALSE)
{
BOOL ok = FALSE;
i_remove_all_items(menu);
ok = DestroyMenu(menu->hmenu);
cassert_unref(ok != 0, ok);
menu->hmenu = NULL;
}
if (menu->hmenu == NULL)
{
menu->hmenu = CreatePopupMenu();
i_add_all_items(menu);
menu->is_popup = TRUE;
}
{
HWND hwnd = NULL;
BOOL ok = FALSE;
UINT flags = TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_NOANIMATION;
hwnd = _oswindow_set_current_popup_menu(window, menu->hmenu);
ok = TrackPopupMenu(menu->hmenu, flags, (int)x, (int)y, PARAM(nReserved, 0), hwnd, NULL);
cassert_unref(ok != 0, ok);
}
}
void osmenu_hide(OSMenu *menu)
{
BOOL ok = FALSE;
cassert_no_null(menu);
unref(menu);
ok = EndMenu();
cassert_unref(ok != 0, ok);
}
bool_t osmenu_is_menubar(const OSMenu *menu)
{
cassert_no_null(menu);
if (menu->window != NULL)
{
cassert_no_null(menu->hmenu);
cassert(menu->is_popup == FALSE);
return TRUE;
}
else
{
return FALSE;
}
}
HMENU _osmenu_hmenu(OSMenu *menu)
{
cassert_no_null(menu);
return menu->hmenu;
}
HMENU _osmenu_menubar(OSMenu *menu, OSWindow *window)
{
cassert_no_null(menu);
cassert(menu->window == NULL);
if (menu->hmenu != NULL && menu->is_popup == TRUE)
{
BOOL ok = FALSE;
i_remove_all_items(menu);
ok = DestroyMenu(menu->hmenu);
cassert_unref(ok != 0, ok);
menu->hmenu = NULL;
menu->is_popup = FALSE;
}
if (menu->hmenu == NULL)
{
menu->hmenu = CreateMenu();
i_add_all_items(menu);
menu->is_popup = FALSE;
}
menu->window = window;
return menu->hmenu;
}
HMENU _osmenu_menubar_unlink(OSMenu *menu, OSWindow *window)
{
cassert_no_null(menu);
cassert_unref(menu->window == window, window);
cassert(menu->is_popup == FALSE);
menu->window = NULL;
return menu->hmenu;
}
void _osmenu_hmenu_recompute(OSMenu *menu)
{
cassert_no_null(menu);
if (menu->hmenu != NULL)
{
i_remove_all_items(menu);
i_add_all_items(menu);
if (menu->window != NULL)
{
HWND hwnd = cast(menu->window, OSControl)->hwnd;
BOOL ok = DrawMenuBar(hwnd);
cassert_unref(ok != 0, ok);
}
}
}
void _osmenu_hmenu_redraw(OSMenu *menu)
{
cassert_no_null(menu);
if (menu->hmenu != NULL && menu->window != NULL)
{
HWND hwnd = cast(menu->window, OSControl)->hwnd;
BOOL ok = DrawMenuBar(hwnd);
cassert_unref(ok != 0, ok);
}
}
void _osmenu_attach_to_item(OSMenu *menu, OSMenuItem *item)
{
cassert_no_null(menu);
cassert(menu->parent == NULL);
menu->parent = item;
if (menu->hmenu == NULL)
{
menu->hmenu = CreatePopupMenu();
menu->is_popup = TRUE;
i_add_all_items(menu);
}
}
void _osmenu_detach_from_item(OSMenu *menu, OSMenuItem *item)
{
cassert_no_null(menu);
cassert_unref(menu->parent == item, item);
menu->parent = NULL;
}