////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include "NstApplicationException.hpp"
#include "NstWindowParam.hpp"
#include "NstWindowMenu.hpp"
namespace Nestopia
{
namespace Window
{
Menu::Instances::Translator Menu::Instances::translator = Menu::Instances::TranslateNone;
Menu::Instances::Menus Menu::Instances::menus;
bool Menu::Instances::acceleratorsEnabled = true;
void Menu::Instances::Update()
{
if (acceleratorsEnabled && menus.Size())
translator = (menus.Size() == 1 ? TranslateSingle : TranslateMulti);
else
translator = TranslateNone;
}
void Menu::Instances::Update(Menu* const menu)
{
const bool useful = menu->acceleratorEnabled && menu->accelerator.Enabled();
if (Instances::Menus::Iterator const instance = menus.Find( menu ))
{
if (!useful)
{
menus.Erase( instance );
Update();
}
}
else
{
if (useful)
{
menus.PushBack( menu );
Update();
}
}
}
void Menu::Instances::Remove(Menu* const menu)
{
if (Instances::Menus::Iterator const instance = menus.Find( menu ))
{
menus.Erase( instance );
Update();
}
}
void Menu::Instances::EnableAccelerators(const bool enable)
{
acceleratorsEnabled = enable;
Update();
}
Menu::PopupHandler::Key Menu::PopupHandler::GetKey(const uint levels) const
{
NST_ASSERT
(
((levels >> 0 & 0xFF) < IDM_OFFSET) &&
((levels >> 8 & 0xFF) < IDM_OFFSET) &&
((levels >> 16 & 0xFF) < IDM_OFFSET) &&
((levels >> 24 & 0xFF) < IDM_OFFSET)
);
HMENU hMenu = menu.handle;
uint pos = levels & 0xFF;
if ( levels & 0x0000FF00 ) { hMenu = ::GetSubMenu( hMenu, pos ); pos = (( levels >> 8 ) - 1) & 0xFF; }
if ( levels & 0x00FF0000 ) { hMenu = ::GetSubMenu( hMenu, pos ); pos = (( levels >> 16 ) - 2) & 0xFF; }
if ( levels & 0xFF000000 ) { hMenu = ::GetSubMenu( hMenu, pos ); pos = (( levels >> 24 ) - 3) & 0xFF; }
return Key( menu.window, hMenu, pos );
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("t", on)
#endif
bool Menu::Instances::TranslateNone(MSG&)
{
NST_ASSERT( !acceleratorsEnabled || menus.Empty() );
return false;
}
bool Menu::Instances::TranslateSingle(MSG& msg)
{
NST_ASSERT( acceleratorsEnabled && menus.Size() == 1 );
return msg.hwnd == *menus.Front()->window ? menus.Front()->accelerator.Translate( msg ) : false;
}
bool Menu::Instances::TranslateMulti(MSG& msg)
{
NST_ASSERT( acceleratorsEnabled && menus.Size() >= 2 );
Menus::ConstIterator menu = menus.Begin();
Menus::ConstIterator const end = menus.End();
do
{
if (msg.hwnd == *(*menu)->window)
return (*menu)->accelerator.Translate( msg );
}
while (++menu != end);
return false;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
Menu::Menu(const uint id)
:
handle ( id ),
window ( NULL ),
acceleratorEnabled ( true )
{
if (!handle)
throw Application::Exception( IDS_ERR_FAILED, L"LoadMenu()" );
}
Menu::~Menu()
{
Unhook();
}
void Menu::Hook(Custom& w)
{
static const MsgHandler::Entry