axmol/templates/lua-template-runtime/frameworks/runtime-src/proj.win32/service/PlayerMenuServiceWin.cpp

352 lines
9.8 KiB
C++

#include "PlayerMenuServiceWin.h"
PLAYER_NS_BEGIN
PlayerMenuItemWin *PlayerMenuItemWin::create(const std::string &menuId, const std::string &title)
{
PlayerMenuItemWin *item = new PlayerMenuItemWin();
item->_menuId = menuId;
item->_title = title;
item->autorelease();
return item;
}
PlayerMenuItemWin::PlayerMenuItemWin()
: _parent(nullptr)
, _commandId(0)
, _hmenu(NULL)
, _menubarEnabled(true)
{
}
PlayerMenuItemWin::~PlayerMenuItemWin()
{
CC_SAFE_RELEASE(_parent);
if (_hmenu)
{
CCLOG("PlayerMenuItemWin::~PlayerMenuItemWin() - %s (HMENU)", _menuId.c_str());
DestroyMenu(_hmenu);
}
else
{
CCLOG("PlayerMenuItemWin::~PlayerMenuItemWin() - %s", _menuId.c_str());
}
}
void PlayerMenuItemWin::setTitle(const std::string &title)
{
if (title.length() == 0)
{
CCLOG("MenuServiceWin::setTitle() - can not set menu title to empty, menu id (%s)", _menuId.c_str());
return;
}
MENUITEMINFO menuitem;
menuitem.cbSize = sizeof(menuitem);
menuitem.fMask = MIIM_FTYPE | MIIM_STRING;
menuitem.fType = (title.compare("-") == 0) ? MFT_SEPARATOR : MFT_STRING;
std::u16string u16title;
cocos2d::StringUtils::UTF8ToUTF16(title, u16title);
menuitem.dwTypeData = (LPTSTR)u16title.c_str();
if (SetMenuItemInfo(_parent->_hmenu, _commandId, MF_BYCOMMAND, &menuitem))
{
_title = title;
}
else
{
DWORD err = GetLastError();
CCLOG("MenuServiceWin::setTitle() - set menu title failed, menu id (%s). error code = %u", _menuId.c_str(), err);
}
}
void PlayerMenuItemWin::setEnabled(bool enabled)
{
MENUITEMINFO menuitem = {0};
menuitem.cbSize = sizeof(menuitem);
menuitem.fMask = MIIM_STATE;
menuitem.fState = (enabled && _menubarEnabled) ? MFS_ENABLED : MFS_DISABLED;
if (SetMenuItemInfo(_parent->_hmenu, _commandId, MF_BYCOMMAND, &menuitem))
{
_isEnabled = enabled;
}
else
{
DWORD err = GetLastError();
CCLOG("MenuServiceWin::setEnabled() - set menu enabled failed, menu id (%s). error code = %u", _menuId.c_str(), err);
}
}
void PlayerMenuItemWin::setChecked(bool checked)
{
MENUITEMINFO menuitem;
menuitem.cbSize = sizeof(menuitem);
menuitem.fMask = MIIM_STATE;
menuitem.fState = (checked) ? MFS_CHECKED : MFS_UNCHECKED;
if (SetMenuItemInfo(_parent->_hmenu, _commandId, MF_BYCOMMAND, &menuitem))
{
_isChecked = checked;
}
else
{
DWORD err = GetLastError();
CCLOG("MenuServiceWin::setChecked() - set menu checked failed, menu id (%s). error code = %u", _menuId.c_str(), err);
}
}
void PlayerMenuItemWin::setShortcut(const std::string &shortcut)
{
}
// MenuServiceWin
WORD PlayerMenuServiceWin::_newCommandId = 0x1000;
PlayerMenuServiceWin::PlayerMenuServiceWin(HWND hwnd)
: _hwnd(hwnd)
, _menubarEnabled(true)
{
// create menu
_root._menuId = "__ROOT__";
_root._commandId = 0;
// hwnd has menu
HMENU menu = GetMenu(hwnd);
if (menu)
{
_root._hmenu = menu;
}
else
{
_root._hmenu = CreateMenu();
SetMenu(hwnd, _root._hmenu);
}
}
PlayerMenuServiceWin::~PlayerMenuServiceWin()
{
}
PlayerMenuItem *PlayerMenuServiceWin::addItem(const std::string &menuId,
const std::string &title,
const std::string &parentId,
int order /* = MAX_ORDER */)
{
if (menuId.length() == 0 || title.length() == 0)
{
CCLOG("MenuServiceWin::addItem() - menuId and title must is non-empty");
return nullptr;
}
// check menu id is exists
if (_items.find(menuId) != _items.end())
{
CCLOG("MenuServiceWin::addItem() - menu id (%s) is exists", menuId.c_str());
return false;
}
// set parent
PlayerMenuItemWin *parent = &_root;
if (parentId.length())
{
// query parent menu
auto it = _items.find(parentId);
if (it != _items.end())
{
parent = it->second;
}
}
if (!parent->_hmenu)
{
// create menu handle for parent (convert parent to submenu)
parent->_hmenu = CreateMenu();
parent->_isGroup = true;
MENUITEMINFO menuitem;
menuitem.cbSize = sizeof(menuitem);
menuitem.fMask = MIIM_SUBMENU;
menuitem.hSubMenu = parent->_hmenu;
if (!SetMenuItemInfo(parent->_parent->_hmenu, parent->_commandId, MF_BYCOMMAND, &menuitem))
{
DWORD err = GetLastError();
CCLOG("MenuServiceWin::addItem() - set menu handle failed, menu id (%s). error code = %u", parent->_menuId.c_str(), err);
return nullptr;
}
}
// create new menu item
_newCommandId++;
PlayerMenuItemWin *item = PlayerMenuItemWin::create(menuId, title);
item->_commandId = _newCommandId;
item->_parent = parent;
item->_parent->retain();
// add menu item to menu bar
MENUITEMINFO menuitem;
menuitem.cbSize = sizeof(menuitem);
menuitem.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_STRING;
menuitem.fType = (item->_title.compare("-") == 0) ? MFT_SEPARATOR : MFT_STRING;
menuitem.fState = (item->_isEnabled) ? MFS_ENABLED : MFS_DISABLED;
menuitem.fState |= (item->_isChecked) ? MFS_CHECKED : MFS_UNCHECKED;
std::u16string u16title;
cocos2d::StringUtils::UTF8ToUTF16(item->_title, u16title);
menuitem.dwTypeData = (LPTSTR)u16title.c_str();
menuitem.wID = _newCommandId;
// check new menu item position
if (order > parent->_children.size())
{
order = parent->_children.size();
}
else if (order < 0)
{
order = 0;
}
// create new menu item
if (!InsertMenuItem(parent->_hmenu, order, TRUE, &menuitem))
{
DWORD err = GetLastError();
CCLOG("MenuServiceWin::addItem() - insert new menu item failed, menu id (%s). error code = %u", item->_menuId.c_str(), err);
item->release();
return nullptr;
}
// update menu state
parent->_children.insert(order, item);
_items[item->_menuId] = item;
_commandId2menuId[item->_commandId] = item->_menuId;
updateChildrenOrder(parent);
return item;
}
PlayerMenuItem *PlayerMenuServiceWin::addItem(const std::string &menuId,
const std::string &title)
{
return addItem(menuId, title, "");
}
PlayerMenuItem *PlayerMenuServiceWin::getItem(const std::string &menuId)
{
auto it = _items.find(menuId);
if (it == _items.end())
{
CCLOG("MenuServiceWin::getItem() - Invalid menu id (%s)", menuId.c_str());
return nullptr;
}
return it->second;
}
bool PlayerMenuServiceWin::removeItem(const std::string &menuId)
{
return removeItemInternal(menuId, true);
}
void PlayerMenuServiceWin::setMenuBarEnabled(bool enabled)
{
_menubarEnabled = enabled;
UINT state = enabled ? MFS_ENABLED : MFS_DISABLED;
for (auto it = _root._children.begin(); it != _root._children.end(); ++it)
{
PlayerMenuItemWin *item = *it;
MENUITEMINFO menuitem = {0};
menuitem.cbSize = sizeof(menuitem);
menuitem.fMask = MIIM_STATE;
menuitem.fState = state;
SetMenuItemInfo(item->_parent->_hmenu, item->_commandId, MF_BYCOMMAND, &menuitem);
item->_menubarEnabled = enabled;
}
}
PlayerMenuItemWin *PlayerMenuServiceWin::getItemByCommandId(WORD commandId)
{
auto it = _commandId2menuId.find(commandId);
if (it == _commandId2menuId.end()) return nullptr;
return _items[it->second];
}
bool PlayerMenuServiceWin::removeItemInternal(const std::string &menuId, bool isUpdateChildrenOrder)
{
auto it = _items.find(menuId);
if (it == _items.end())
{
CCLOG("MenuServiceWin::removeItem() - Invalid menu id (%s)", menuId.c_str());
return false;
}
PlayerMenuItemWin *item = it->second;
if (item->_children.size() == 0)
{
if (!DeleteMenu(item->_parent->_hmenu, item->_commandId, MF_BYCOMMAND))
{
DWORD err = GetLastError();
CCLOG("MenuServiceWin::removeItem() - remove menu item failed, menu id (%s). error code = %u", item->_menuId.c_str(), err);
return false;
}
// remove item from parent
bool removed = false;
auto *children = &item->_parent->_children;
for (auto it = children->begin(); it != children->end(); ++it)
{
if ((*it)->_commandId == item->_commandId)
{
CCLOG("MenuServiceWin::removeItem() - remove menu item (%s)", item->_menuId.c_str());
children->erase(it);
removed = true;
break;
}
}
if (!removed)
{
CCLOG("MenuServiceWin::removeItem() - remove menu item (%s) failed, not found command id from parent->children", item->_menuId.c_str());
}
// remove menu id mapping
_items.erase(menuId);
_commandId2menuId.erase(item->_commandId);
if (isUpdateChildrenOrder)
{
updateChildrenOrder(item->_parent);
}
DrawMenuBar(_hwnd);
return true;
}
else
{
// remove all children
while (item->_children.size() != 0)
{
PlayerMenuItemWin *child = *item->_children.begin();
if (!removeItemInternal(child->_menuId.c_str(), false))
{
break;
return false;
}
}
return removeItemInternal(menuId, true);
}
return false;
}
void PlayerMenuServiceWin::updateChildrenOrder(PlayerMenuItemWin *parent)
{
auto *children = &parent->_children;
int order = 0;
for (auto it = children->begin(); it != children->end(); ++it)
{
(*it)->_order = order;
order++;
}
}
PLAYER_NS_END