#include "stdafx.h"
#include "hwinmenu.h"
#include "hwinexception.h"
#include "hwincontrol.h"
namespace harlinn
{
namespace windows
{
// ----------------------------------------------------------------------
// MenuItem
// ----------------------------------------------------------------------
HWIN_EXPORT MenuItem::MenuItem()
: Base( ),
checked(false),
isDefault(false),
disabled(false),
grayed(false),
highlighted(false),
menuBarBreak(false),
menuBreak(false),
ownerDraw(false)
{
}
HWIN_EXPORT MenuItem::~MenuItem( )
{
}
HWIN_EXPORT std::shared_ptr<MenuItems> MenuItem::ParentMenuItems() const
{
auto menu = ParentMenu();
if(menu)
{
auto result = menu->Items();
return result;
}
else
{
return nullptr;
}
}
HWIN_EXPORT std::shared_ptr<Menu> MenuItem::ParentMenu() const
{
auto theParentMenu = parentMenu.lock();
return theParentMenu;
}
HWIN_EXPORT int MenuItem::IndexOf( ) const
{
auto mnuItems = ParentMenuItems();
if(mnuItems)
{
return mnuItems->IndexOf(As<MenuItem>());
}
return -1;
}
HWIN_EXPORT std::shared_ptr<BitmapHandle> MenuItem::Bitmap() const
{
return bitmap;
}
HWIN_EXPORT MenuItem& MenuItem::SetBitmap(std::shared_ptr<BitmapHandle> theBitmap)
{
if(bitmap != theBitmap)
{
bitmap = theBitmap;
this->UpdateMenuItem();
}
return *this;
}
HWIN_EXPORT std::shared_ptr<BitmapHandle> MenuItem::CheckedBitmap() const
{
return checkedBitmap;
}
HWIN_EXPORT MenuItem& MenuItem::SetCheckedBitmap(std::shared_ptr<BitmapHandle> theCheckedBitmap)
{
if(checkedBitmap != theCheckedBitmap)
{
checkedBitmap = theCheckedBitmap;
this->UpdateMenuItem();
}
return *this;
}
HWIN_EXPORT std::shared_ptr<BitmapHandle> MenuItem::UncheckedBitmap() const
{
return uncheckedBitmap;
}
HWIN_EXPORT MenuItem& MenuItem::SetUncheckedBitmap(std::shared_ptr<BitmapHandle> theUncheckedBitmap)
{
if(uncheckedBitmap != theUncheckedBitmap)
{
uncheckedBitmap = theUncheckedBitmap;
this->UpdateMenuItem();
}
return *this;
}
HWIN_EXPORT bool MenuItem::IsChecked() const
{
return checked;
}
HWIN_EXPORT MenuItem& MenuItem::SetChecked(bool value)
{
if(checked != value)
{
checked = value;
this->UpdateMenuItem();
}
return *this;
}
HWIN_EXPORT bool MenuItem::IsDefault() const
{
return isDefault;
}
HWIN_EXPORT MenuItem& MenuItem::SetDefault(bool value)
{
if(isDefault != value)
{
isDefault = value;
this->UpdateMenuItem();
}
return *this;
}
HWIN_EXPORT bool MenuItem::IsDisabled() const
{
return disabled;
}
HWIN_EXPORT MenuItem& MenuItem::SetDisabled(bool value)
{
if(disabled != value)
{
disabled = value;
this->UpdateMenuItem();
}
return *this;
}
HWIN_EXPORT bool MenuItem::IsEnabled() const
{
return (disabled || grayed) == false;
}
HWIN_EXPORT MenuItem& MenuItem::SetEnabled(bool value)
{
return SetDisabled(value?false:true);
}
HWIN_EXPORT bool MenuItem::IsGrayed() const
{
return grayed;
}
HWIN_EXPORT MenuItem& MenuItem::SetGrayed(bool value)
{
if(grayed != value)
{
grayed = value;
this->UpdateMenuItem();
}
return *this;
}
HWIN_EXPORT bool MenuItem::IsHighlighted() const
{
return highlighted;
}
HWIN_EXPORT MenuItem& MenuItem::SetHighlighted(bool value)
{
if(highlighted != value)
{
highlighted = value;
this->UpdateMenuItem();
}
return *this;
}
HWIN_EXPORT MenuItem& MenuItem::DoOnAdd()
{
auto menu = ParentMenu();
if(menu)
{
MENUITEMINFO info;
this->InitializeMenuItemInfo(info);
auto index = IndexOf();
menu->GetHandle()->InsertMenuItem(index,true,info);
}
return *this;
}
HWIN_EXPORT MenuItem& MenuItem::DoOnRemove()
{
auto menu = ParentMenu();
if(menu)
{
auto index = IndexOf();
if(index >= 0)
{
if(menu->GetHandle()->IsMenu())
{
menu->GetHandle()->RemoveMenu(index,MF_BYPOSITION);
}
}
}
return *this;
}
HWIN_EXPORT const MenuItem& MenuItem::InitializeMenuItemInfo(MENUITEMINFO& info) const
{
memset(&info,0,sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask |= MIIM_DATA | MIIM_STATE | MIIM_FTYPE;
info.dwItemData = (ULONG_PTR)this;
if(bitmap)
{
info.fMask |= MIIM_BITMAP;
info.hbmpItem = bitmap->GetHBITMAP();
}
if(checkedBitmap)
{
info.fMask |= MIIM_CHECKMARKS;
info.hbmpChecked = checkedBitmap->GetHBITMAP();
}
if(uncheckedBitmap)
{
info.fMask |= MIIM_CHECKMARKS;
info.hbmpUnchecked = uncheckedBitmap->GetHBITMAP();
}
if(checked)
{
info.fState |= MFS_CHECKED;
}
if(isDefault)
{
info.fState |= MFS_DEFAULT;
}
if(disabled)
{
info.fState |= MFS_DISABLED;
}
if(grayed)
{
info.fState |= MFS_GRAYED;
}
if(highlighted)
{
info.fState |= MFS_HILITE;
}
if(menuBarBreak)
{
info.fType |= MFT_MENUBARBREAK;
}
if(menuBreak)
{
info.fType |= MFT_MENUBREAK;
}
if(ownerDraw)
{
info.fType |= MFT_OWNERDRAW;
}
return *this;
}
HWIN_EXPORT const MenuItem& MenuItem::UpdateMenuItem() const
{
auto menuItems = ParentMenuItems();
if(menuItems)
{
MENUITEMINFO info;
this->InitializeMenuItemInfo(info);
int index = IndexOf();
auto menu = ParentMenu();
menu->GetHandle()->SetMenuItemInfo(index,true,&info);
}
return *this;
}
HWIN_EXPORT void MenuItem::DoOnMenuCommand(Message& message)
{
OnClick( this );
}
HWIN_EXPORT void MenuItem::DoOnMeasureItem(MEASUREITEMSTRUCT& measureItemStruct)
{
OnMeasureItem(this,measureItemStruct);
}
HWIN_EXPORT void MenuItem::DoOnDrawItem(DRAWITEMSTRUCT& drawItemStruct)
{
OnDrawItem(this,drawItemStruct);
}
// ----------------------------------------------------------------------
// TextMenuItem
// ----------------------------------------------------------------------
HWIN_EXPORT TextMenuItem::TextMenuItem(const wchar_t* theText)
: Base(), text(theText)
{}
HWIN_EXPORT TextMenuItem::TextMenuItem(const String& theText)
: Base(), text(theText)
{}
HWIN_EXPORT const MenuItem& TextMenuItem::InitializeMenuItemInfo(MENUITEMINFO& info) const
{
Base::InitializeMenuItemInfo(info);
info.fMask |= MIIM_STRING;
info.cch = (UINT)text.length();
info.dwTypeData = (LPTSTR)text.c_str();
return *this;
}
HWIN_EXPORT TextMenuItem& TextMenuItem::SetText(const wchar_t* theText)
{
text = theText;
this->UpdateMenuItem();
return *this;
}
HWIN_EXPORT TextMenuItem& TextMenuItem::SetText(const String& theText)
{
text = theText;
this->UpdateMenuItem();
return *this;
}
HWIN_EXPORT const String& TextMenuItem::Text() const
{
return text;
}
HWIN_EXPORT String TextMenuItem::Text()
{
return text;
}
// ----------------------------------------------------------------------
// SeparatorMenuItem
// ----------------------------------------------------------------------
HWIN_EXPORT SeparatorMenuItem::SeparatorMenuItem( )
: Base( )
{}
HWIN_EXPORT MenuItem& SeparatorMenuItem::DoOnAdd()
{
auto menu = ParentMenu();
if(menu)
{
menu->GetHandle()->AppendMenu(MF_SEPARATOR,0,nullptr);
}
return *this;
}
// ----------------------------------------------------------------------
// SubMenuItem
// ----------------------------------------------------------------------
HWIN_EXPORT SubMenuItem::SubMenuItem(const wchar_t* theText)
: Base( ), text(theText)
{}
HWIN_EXPORT SubMenuItem::SubMenuItem(const String& theText)
: Base( ), text(theText)
{}
HWIN_EXPORT std::shared_ptr<Menu> SubMenuItem::Menu() const
{
if(!menu)
{
auto hMenu = ::CreatePopupMenu();
if(!hMenu)
{
ThrowLastOSError();
}
auto menuHandle = std::make_shared<MenuHandle>(hMenu,true);
menu = std::make_shared<harlinn::windows::Menu>(menuHandle);
menu->AddStyle(MNS_NOTIFYBYPOS);
}
return menu;
}
HWIN_EXPORT std::shared_ptr<const MenuItems> SubMenuItem::Items() const
{
auto menu = Menu();
if(menu)
{
return menu->Items();
}
return nullptr;
}
HWIN_EXPORT std::shared_ptr<MenuItems> SubMenuItem::Items()
{
auto menu = Menu();
if(menu)
{
return menu->Items();
}
return nullptr;
}
HWIN_EXPORT SubMenuItem& SubMenuItem::Add(std::shared_ptr<MenuItem> menuItem)
{
auto theItems = Items();
if(theItems)
{
theItems->Add(menuItem);
}
return *this;
}
HWIN_EXPORT SubMenuItem& SubMenuItem::Remove(std::shared_ptr<MenuItem> menuItem)
{
auto theItems = Items();
if(theItems)
{
theItems->Remove(menuItem);
}
return *this;
}
HWIN_EXPORT std::shared_ptr<TextMenuItem> SubMenuItem::AddMenuItem(const wchar_t* theText)
{
auto theMenu = Menu();
if(theMenu)
{
auto result = theMenu->AddMenuItem(theText);
return result;
}
return nullptr;
}
HWIN_EXPORT std::shared_ptr<TextMenuItem> SubMenuItem::AddMenuItem(const String& theText)
{
auto theMenu = Menu();
if(theMenu)
{
auto result = theMenu->AddMenuItem(theText);
return result;
}
return nullptr;
}
HWIN_EXPORT std::shared_ptr<SeparatorMenuItem> SubMenuItem::AddSeparator()
{
auto theMenu = Menu();
if(theMenu)
{
auto result = theMenu->AddSeparator();
return result;
}
return nullptr;
}
HWIN_EXPORT std::shared_ptr<SubMenuItem> SubMenuItem::AddSubMenu(const wchar_t* theText)
{
auto theMenu = Menu();
if(theMenu)
{
auto result = theMenu->AddSubMenu(theText);
return result;
}
return nullptr;
}
HWIN_EXPORT std::shared_ptr<SubMenuItem> SubMenuItem::AddSubMenu(const String& theText)
{
auto theMenu = Menu();
if(theMenu)
{
auto result = theMenu->AddSubMenu(theText);
return result;
}
return nullptr;
}
HWIN_EXPORT const MenuItem& SubMenuItem::InitializeMenuItemInfo(MENUITEMINFO& info) const
{
Base::InitializeMenuItemInfo(info);
info.fMask |= MIIM_STRING;
info.cch = (UINT)text.length();
info.dwTypeData = (LPTSTR)text.c_str();
auto theMenu = Menu();
info.fMask |= MIIM_SUBMENU;
info.hSubMenu = theMenu->GetHandle()->GetHMENU();
return *this;
}
// ----------------------------------------------------------------------
// MenuItems
// ----------------------------------------------------------------------
HWIN_EXPORT MenuItems::MenuItems(harlinn::windows::Menu* theOwner)
: owner(theOwner)
{
}
HWIN_EXPORT MenuItems::~MenuItems( )
{
for (auto item:items)
{
item->parentMenu = std::weak_ptr<harlinn::windows::Menu>();
}
}
HWIN_EXPORT std::shared_ptr<Menu> MenuItems::Menu() const
{
if(owner)
{
return owner->As<harlinn::windows::Menu>();
}
return std::shared_ptr<harlinn::windows::Menu>();
}
HWIN_EXPORT MenuItems& MenuItems::Add(std::shared_ptr<MenuItem> menuItem)
{
if(menuItem)
{
auto previousMenu = menuItem->ParentMenu();
auto thisMenu = Menu();
if(previousMenu != thisMenu)
{
if(previousMenu)
{
previousMenu->Items()->Remove(menuItem);
}
menuItem->parentMenu = thisMenu;
items.push_back(menuItem);
menuItem->DoOnAdd();
}
}
return *this;
}
HWIN_EXPORT MenuItems& MenuItems::Remove(std::shared_ptr<MenuItem> menuItem)
{
if(menuItem)
{
int index = IndexOf(menuItem);
menuItem->DoOnRemove();
menuItem->parentMenu = std::weak_ptr<harlinn::windows::Menu>();
items.erase(items.begin()+index);
}
return *this;
}
HWIN_EXPORT std::shared_ptr<TextMenuItem> MenuItems::AddMenuItem(const wchar_t* theText)
{
auto theMenu = Menu();
auto result = make_component<TextMenuItem>(theMenu,theText);
Add(result);
return result;
}
HWIN_EXPORT std::shared_ptr<TextMenuItem> MenuItems::AddMenuItem(const String& theText)
{
auto theMenu = Menu();
auto result = make_component<TextMenuItem>(theMenu,theText);
Add(result);
return result;
}
HWIN_EXPORT std::shared_ptr<SeparatorMenuItem> MenuItems::AddSeparator()
{
auto theMenu = Menu();
auto result = make_component<SeparatorMenuItem>(theMenu);
Add(result);
return result;
}
HWIN_EXPORT std::shared_ptr<SubMenuItem> MenuItems::AddSubMenu(const wchar_t* theText)
{
auto theMenu = Menu();
auto result = make_component<SubMenuItem>(theMenu,theText);
Add(result);
return result;
}
HWIN_EXPORT std::shared_ptr<SubMenuItem> MenuItems::AddSubMenu(const String& theText)
{
auto theMenu = Menu();
auto result = make_component<SubMenuItem>(theMenu,theText);
Add(result);
return result;
}
HWIN_EXPORT int MenuItems::IndexOf(std::shared_ptr<const MenuItem> menuItem) const
{
if(menuItem)
{
for(vector::size_type i = 0; i < items.size(); i++)
{
auto item = items.at(i);
if(item == menuItem)
{
return (int)i;
}
}
}
return -1;
}
HWIN_EXPORT std::shared_ptr<const MenuItem> MenuItems::Item(int position) const
{
if(position >= 0 && static_cast<vector::size_type>( position ) < items.size())
{
auto item = items.at(position);
return item;
}
return nullptr;
}
HWIN_EXPORT std::shared_ptr<MenuItem> MenuItems::Item(int position)
{
if(position >= 0 && static_cast<vector::size_type>( position ) < items.size())
{
auto item = items.at(position);
return item;
}
return nullptr;
}
// ----------------------------------------------------------------------
// Menu
// ----------------------------------------------------------------------
std::map<HMENU,Menu*> Menu::menuMap;
HWIN_EXPORT void Menu::AddToMenuMap(HMENU hMenu, Menu* theMenu)
{
CheckPointerNotNull(theMenu);
CheckPointerNotNull(hMenu);
auto it = menuMap.find(hMenu);
if(it == menuMap.end())
{
menuMap.insert(std::map<HMENU,Menu*>::value_type(hMenu,theMenu));
}
}
HWIN_EXPORT void Menu::RemoveFromMenuMap(HMENU hMenu)
{
CheckPointerNotNull(hMenu);
auto it = menuMap.find(hMenu);
if(it != menuMap.end())
{
menuMap.erase(it);
}
}
HWIN_EXPORT Menu* Menu::GetFromMenuMap(HMENU hMenu)
{
if(hMenu)
{
auto it = menuMap.find(hMenu);
if(it != menuMap.end())
{
auto result = (*it).second;
return result;
}
}
return nullptr;
}
HWIN_EXPORT Menu::Menu(std::shared_ptr<MenuHandle> menuHandle)
: Base( ),
handle( menuHandle )
{
if(menuHandle)
{
HMENU hMenu = menuHandle->GetHMENU();
if(hMenu)
{
AddToMenuMap(hMenu,this);
}
}
items = std::make_shared<MenuItems>(this);
}
HWIN_EXPORT Menu::~Menu( )
{
if(handle)
{
HMENU hMenu = handle->GetHMENU();
if(hMenu)
{
RemoveFromMenuMap(hMenu);
}
}
items->owner = nullptr;
}
std::shared_ptr<MenuHandle> Menu::GetHandle()
{
return handle;
}
HWIN_EXPORT std::shared_ptr<const MenuItems> Menu::Items() const
{
return items;
}
HWIN_EXPORT std::shared_ptr<MenuItems> Menu::Items()
{
return items;
}
HWIN_EXPORT std::shared_ptr<const MenuItem> Menu::Item(int position) const
{
return items->Item(position);
}
HWIN_EXPORT std::shared_ptr<MenuItem> Menu::Item(int position)
{
return items->Item(position);
}
HWIN_EXPORT Menu& Menu::AddStyle(DWORD style)
{
handle->AddStyle(style);
return *this;
}
HWIN_EXPORT Menu& Menu::Add(std::shared_ptr<MenuItem> menuItem)
{
auto theItems = Items();
if(theItems)
{
theItems->Add(menuItem);
}
return *this;
}
HWIN_EXPORT Menu& Menu::Remove(std::shared_ptr<MenuItem> menuItem)
{
auto theItems = Items();
if(theItems)
{
theItems->Remove(menuItem);
}
return *this;
}
HWIN_EXPORT std::shared_ptr<TextMenuItem> Menu::AddMenuItem(const wchar_t* theText)
{
auto theItems = Items();
if(theItems)
{
auto result = theItems->AddMenuItem(theText);
return result;
}
return nullptr;
}
HWIN_EXPORT std::shared_ptr<TextMenuItem> Menu::AddMenuItem(const String& theText)
{
auto theItems = Items();
if(theItems)
{
auto result = theItems->AddMenuItem(theText);
return result;
}
return nullptr;
}
HWIN_EXPORT std::shared_ptr<SeparatorMenuItem> Menu::AddSeparator()
{
auto theItems = Items();
if(theItems)
{
auto result = theItems->AddSeparator();
return result;
}
return nullptr;
}
HWIN_EXPORT std::shared_ptr<SubMenuItem> Menu::AddSubMenu(const wchar_t* theText)
{
auto theItems = Items();
if(theItems)
{
auto result = theItems->AddSubMenu(theText);
return result;
}
return nullptr;
}
HWIN_EXPORT std::shared_ptr<SubMenuItem> Menu::AddSubMenu(const String& theText)
{
auto theItems = Items();
auto result = theItems->AddSubMenu(theText);
return result;
}
HWIN_EXPORT void Menu::DoOnInitMenu(Message& message)
{
OnInitMenu(message);
}
HWIN_EXPORT void Menu::DoOnInitMenuPopup(Message& message)
{
OnInitMenuPopup(message);
}
HWIN_EXPORT void Menu::DoOnMenuCommand(Message& message)
{
OnMenuCommand(message);
if(!message.handled)
{
int position = (int)message.wParam;
auto item = Item(position);
if(item)
{
item->DoOnMenuCommand(message);
}
}
}
// ----------------------------------------------------------------------
// MenuBar
// ----------------------------------------------------------------------
HWIN_EXPORT std::shared_ptr<MenuHandle> MenuBar::CreateHandle()
{
HMENU hMenu = ::CreateMenu();
if(!hMenu)
{
ThrowLastOSError();
}
auto result = std::make_shared<MenuHandle>(hMenu,true);
return result;
}
HWIN_EXPORT MenuBar::MenuBar( )
: Base(CreateHandle())
{
AddStyle(MNS_NOTIFYBYPOS);
}
// ----------------------------------------------------------------------
// PopupMenu
// ----------------------------------------------------------------------
HWIN_EXPORT std::shared_ptr<MenuHandle> PopupMenu::CreateHandle()
{
HMENU hMenu = ::CreatePopupMenu();
if(!hMenu)
{
ThrowLastOSError();
}
auto result = std::make_shared<MenuHandle>(hMenu,true);
return result;
}
PopupMenuAlignment PopupMenu::GetDefaultAlignment()
{
if(::GetSystemMetrics(SM_MENUDROPALIGNMENT))
{
return PopupMenuAlignment::Right | PopupMenuAlignment::Top;
}
else
{
return PopupMenuAlignment::Left | PopupMenuAlignment::Top;
}
}
HWIN_EXPORT PopupMenu::PopupMenu( )
: Base(CreateHandle()),
alignment( GetDefaultAlignment() )
{
AddStyle(MNS_NOTIFYBYPOS);
}
HWIN_EXPORT PopupMenuAlignment PopupMenu::Alignment() const
{
return alignment;
}
HWIN_EXPORT PopupMenu& PopupMenu::SetAlignment(PopupMenuAlignment theAlignment)
{
if(alignment != theAlignment)
{
alignment = theAlignment;
}
return *this;
}
HWIN_EXPORT PopupMenu& PopupMenu::Show(std::shared_ptr<Control> theControl, const POINT& screenPosition)
{
HMENU hMenu = this->GetHandle()->GetHMENU();
int flags = int(alignment);
if(TrackPopupMenuEx(hMenu,flags,screenPosition.x,screenPosition.y,theControl->GetSafeHandle(),nullptr) == FALSE)
{
ThrowLastOSError();
}
return *this;
}
HWIN_EXPORT PopupMenu& PopupMenu::Show(std::shared_ptr<Control> theControl, const POINT& screenPosition, const RECT& excludeArea)
{
HMENU hMenu = this->GetHandle()->GetHMENU();
int flags = int(alignment);
TPMPARAMS tpmparams = {0,};
tpmparams.cbSize = sizeof(TPMPARAMS);
tpmparams.rcExclude = excludeArea;
if(TrackPopupMenuEx(hMenu,flags,screenPosition.x,screenPosition.y,theControl->GetSafeHandle(),&tpmparams) == FALSE)
{
ThrowLastOSError();
}
return *this;
}
}
}