Files
wxWidgets/tests/menu/menu.cpp
Vadim Zeitlin 8d349dbddc Make it possible to call wxMenuItem::GetBitmapBundle() again
The changes of 0dfe37a643 (Add wxMSW-specific wxBitmapBundle accessors
to wxMenuItem, 2025-08-18) broke this as wxMSW-specific function taking
bool hid the base class function.

Just make the wxMSW function compatible with the base class one by
defaulting "bChecked" to false. Alternatively, we could use using
declaration to bring the base class function in scope, but this doesn't
seem to have any advantages and this change seems more clear.

In any case, add a unit test checking that the calls to these functions
at least compile.

See #25685, #25705.

Closes #25719.
2025-08-22 21:25:11 +02:00

869 lines
28 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: tests/menu/menu.cpp
// Purpose: wxMenu unit test
// Author: wxWidgets team
// Created: 2010-11-10
// Copyright: (c) 2010 wxWidgets team
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#if wxUSE_MENUBAR
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include "wx/menu.h"
#include "wx/translation.h"
#include "wx/uiaction.h"
#include "waitfor.h"
#include <stdarg.h>
#include <memory>
// ----------------------------------------------------------------------------
// helper
// ----------------------------------------------------------------------------
namespace
{
enum
{
MenuTestCase_Foo = 10000,
MenuTestCase_SelectAll,
MenuTestCase_Bar,
MenuTestCase_ExtraAccel,
MenuTestCase_ExtraAccels,
MenuTestCase_First
};
void PopulateMenu(wxMenu* menu, const wxString& name, size_t& itemcount)
{
// Start at item 1 to make it human-readable ;)
for (int n=1; n<6; ++n, ++itemcount)
{
wxString label = name; label << n;
menu->Append(MenuTestCase_First + itemcount, label, label + " help string");
}
}
void RecursivelyCountMenuItems(const wxMenu* menu, size_t& count)
{
CPPUNIT_ASSERT( menu );
count += menu->GetMenuItemCount();
for (size_t n=0; n < menu->GetMenuItemCount(); ++n)
{
wxMenuItem* item = menu->FindItemByPosition(n);
if (item->IsSubMenu())
{
RecursivelyCountMenuItems(item->GetSubMenu(), count);
}
}
}
} // anon namespace
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
class MenuTestCase : public CppUnit::TestCase
{
public:
MenuTestCase() {}
virtual void setUp() override { CreateFrame(); }
virtual void tearDown() override { m_frame->Destroy(); }
private:
CPPUNIT_TEST_SUITE( MenuTestCase );
CPPUNIT_TEST( FindInMenubar );
CPPUNIT_TEST( FindInMenu );
CPPUNIT_TEST( EnableTop );
CPPUNIT_TEST( Count );
CPPUNIT_TEST( Labels );
#if wxUSE_INTL
CPPUNIT_TEST( TranslatedMnemonics );
#endif // wxUSE_INTL
CPPUNIT_TEST( RadioItems );
CPPUNIT_TEST( RemoveAdd );
CPPUNIT_TEST( ChangeBitmap );
WXUISIM_TEST( Events );
CPPUNIT_TEST_SUITE_END();
void CreateFrame();
void FindInMenubar();
void FindInMenu();
void EnableTop();
void Count();
void Labels();
#if wxUSE_INTL
void TranslatedMnemonics();
#endif // wxUSE_INTL
void RadioItems();
void RemoveAdd();
void ChangeBitmap();
void Events();
wxFrame* m_frame;
// Holds the number of menuitems contained in all the menus
size_t m_itemCount;
// Store here the id of a known submenu item, to be searched for later
int m_submenuItemId;
// and a sub-submenu item
int m_subsubmenuItemId;
wxArrayString m_menuLabels;
// The menu containing the item with MenuTestCase_Bar id.
wxMenu* m_menuWithBar;
wxDECLARE_NO_COPY_CLASS(MenuTestCase);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( MenuTestCase );
// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MenuTestCase, "MenuTestCase" );
void MenuTestCase::CreateFrame()
{
m_frame = new wxFrame(wxTheApp->GetTopWindow(), wxID_ANY, "test frame");
wxMenu *fileMenu = new wxMenu;
wxMenu *helpMenu = new wxMenu;
wxMenu *subMenu = new wxMenu;
wxMenu *subsubMenu = new wxMenu;
m_itemCount = 0;
PopulateMenu(subsubMenu, "Subsubmenu item ", m_itemCount);
// Store one of its IDs for later
m_subsubmenuItemId = MenuTestCase_First + m_itemCount - 2;
PopulateMenu(subMenu, "Submenu item ", m_itemCount);
// Store one of its IDs for later
m_submenuItemId = MenuTestCase_First + m_itemCount - 2;
subMenu->AppendSubMenu(subsubMenu, "Subsubmen&u", "Test a subsubmenu");
m_itemCount++;
// Check GetTitle() returns the correct string _before_ appending to the bar
fileMenu->SetTitle("&Foo\tCtrl-F");
CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", fileMenu->GetTitle() );
PopulateMenu(fileMenu, "Filemenu item ", m_itemCount);
fileMenu->Append(MenuTestCase_Foo, "&Foo\tCtrl-F", "Test item to be found");
m_itemCount++;
fileMenu->Append(MenuTestCase_SelectAll, "Select &all\tCtrl-A",
"Accelerator conflicting with wxTextCtrl");
m_itemCount++;
// Test adding an extra accelerator to the item before adding it to the menu.
wxAcceleratorEntry entry;
wxMenuItem* const
extraAccel = new wxMenuItem(fileMenu, MenuTestCase_ExtraAccel, "Extra accels");
CHECK( entry.FromString("Ctrl-U") );
extraAccel->SetAccel(&entry);
CHECK( entry.FromString("Ctrl-V") );
extraAccel->AddExtraAccel(entry);
fileMenu->Append(extraAccel);
m_itemCount++;
// And now also test adding 2 of them after creating the initial menu item.
wxMenuItem* const
extraAccels = fileMenu->Append(MenuTestCase_ExtraAccels, "Extra accels 2");
m_itemCount++;
CHECK( entry.FromString("Ctrl-T") );
extraAccels->AddExtraAccel(entry);
CHECK(entry.FromString("Shift-Ctrl-W"));
extraAccels->AddExtraAccel(entry);
CHECK(entry.FromString("Ctrl-W"));
extraAccels->SetAccel(&entry);
PopulateMenu(helpMenu, "Helpmenu item ", m_itemCount);
helpMenu->Append(MenuTestCase_Bar, "Bar\tF1");
m_itemCount++;
m_menuWithBar = helpMenu;
helpMenu->AppendSubMenu(subMenu, "Sub&menu", "Test a submenu");
m_itemCount++;
// Use an arraystring here, to help with future tests
m_menuLabels.Add("&File");
m_menuLabels.Add("&Help");
wxMenuBar *menuBar = new wxMenuBar();
menuBar->Append(fileMenu, m_menuLabels[0]);
menuBar->Append(helpMenu, m_menuLabels[1]);
m_frame->SetMenuBar(menuBar);
}
void MenuTestCase::FindInMenubar()
{
wxMenuBar* bar = m_frame->GetMenuBar();
// Find by name:
CPPUNIT_ASSERT( bar->FindMenu("File") != wxNOT_FOUND );
CPPUNIT_ASSERT( bar->FindMenu("&File") != wxNOT_FOUND );
CPPUNIT_ASSERT( bar->FindMenu("&Fail") == wxNOT_FOUND );
// Find by menu name plus item name:
CPPUNIT_ASSERT( bar->FindMenuItem("File", "Foo") != wxNOT_FOUND );
CPPUNIT_ASSERT( bar->FindMenuItem("&File", "&Foo") != wxNOT_FOUND );
// and using the menu label
int index = bar->FindMenu("&File");
CPPUNIT_ASSERT( index != wxNOT_FOUND );
wxString menulabel = bar->GetMenuLabel(index);
CPPUNIT_ASSERT( bar->FindMenuItem(menulabel, "&Foo") != wxNOT_FOUND );
// and title
wxString menutitle = bar->GetMenu(index)->GetTitle();
CPPUNIT_ASSERT( bar->FindMenuItem(menutitle, "&Foo") != wxNOT_FOUND );
// Find by position:
for (size_t n=0; n < bar->GetMenuCount(); ++n)
{
CPPUNIT_ASSERT( bar->GetMenu(n) );
}
// Find by id:
wxMenu* menu = nullptr;
wxMenuItem* item = nullptr;
item = bar->FindItem(MenuTestCase_Foo, &menu);
CPPUNIT_ASSERT( item );
CPPUNIT_ASSERT( menu );
// Check that the correct menu was found
CPPUNIT_ASSERT( menu->FindChildItem(MenuTestCase_Foo) );
// Find submenu item:
item = bar->FindItem(m_submenuItemId, &menu);
CPPUNIT_ASSERT( item );
CPPUNIT_ASSERT( menu );
// and, for completeness, a subsubmenu one:
item = bar->FindItem(m_subsubmenuItemId, &menu);
CPPUNIT_ASSERT( item );
CPPUNIT_ASSERT( menu );
}
void MenuTestCase::FindInMenu()
{
wxMenuBar* bar = m_frame->GetMenuBar();
// Find by name:
wxMenu* menuFind = bar->GetMenu(0);
CPPUNIT_ASSERT( menuFind->FindItem("Foo") != wxNOT_FOUND );
CPPUNIT_ASSERT( menuFind->FindItem("&Foo") != wxNOT_FOUND );
// and for submenus
wxMenu* menuHelp = bar->GetMenu(1);
CPPUNIT_ASSERT( menuHelp->FindItem("Submenu") != wxNOT_FOUND );
CPPUNIT_ASSERT( menuHelp->FindItem("Sub&menu") != wxNOT_FOUND );
// Find by position:
size_t n;
for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
{
CPPUNIT_ASSERT( menuHelp->FindItemByPosition(n) );
}
// Find by id:
CPPUNIT_ASSERT( menuHelp->FindItem(MenuTestCase_Bar) );
CPPUNIT_ASSERT( !menuHelp->FindItem(MenuTestCase_Foo) );
for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
{
size_t locatedAt;
wxMenuItem* itemByPos = menuHelp->FindItemByPosition(n);
CPPUNIT_ASSERT( itemByPos );
wxMenuItem* itemById = menuHelp->FindChildItem(itemByPos->GetId(), &locatedAt);
CPPUNIT_ASSERT_EQUAL( itemByPos, itemById );
CPPUNIT_ASSERT_EQUAL( locatedAt, n );
}
// Find submenu item:
for (n=0; n < menuHelp->GetMenuItemCount(); ++n)
{
wxMenuItem* item = menuHelp->FindItemByPosition(n);
if (item->IsSubMenu())
{
wxMenu* submenu;
wxMenuItem* submenuItem = menuHelp->FindItem(m_submenuItemId, &submenu);
CPPUNIT_ASSERT( submenuItem );
CPPUNIT_ASSERT( item->GetSubMenu() == submenu );
}
}
}
void MenuTestCase::EnableTop()
{
wxMenuBar* const bar = m_frame->GetMenuBar();
CPPUNIT_ASSERT( bar->IsEnabledTop(0) );
bar->EnableTop( 0, false );
CPPUNIT_ASSERT( !bar->IsEnabledTop(0) );
bar->EnableTop( 0, true );
CPPUNIT_ASSERT( bar->IsEnabledTop(0) );
}
void MenuTestCase::Count()
{
wxMenuBar* bar = m_frame->GetMenuBar();
// I suppose you could call this "counting menubars" :)
CPPUNIT_ASSERT( bar );
CPPUNIT_ASSERT_EQUAL( bar->GetMenuCount(), 2 );
size_t count = 0;
for (size_t n=0; n < bar->GetMenuCount(); ++n)
{
RecursivelyCountMenuItems(bar->GetMenu(n), count);
}
CPPUNIT_ASSERT_EQUAL( count, m_itemCount );
}
void MenuTestCase::Labels()
{
wxMenuBar* bar = m_frame->GetMenuBar();
CPPUNIT_ASSERT( bar );
wxMenu* filemenu;
wxMenuItem* itemFoo = bar->FindItem(MenuTestCase_Foo, &filemenu);
CPPUNIT_ASSERT( itemFoo );
CPPUNIT_ASSERT( filemenu );
// These return labels including mnemonics/accelerators:
// wxMenuBar
CPPUNIT_ASSERT_EQUAL( "&File", bar->GetMenuLabel(0) );
CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", bar->GetLabel(MenuTestCase_Foo) );
// wxMenu
CPPUNIT_ASSERT_EQUAL( "&File", filemenu->GetTitle() );
CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", filemenu->GetLabel(MenuTestCase_Foo) );
// wxMenuItem
CPPUNIT_ASSERT_EQUAL( "&Foo\tCtrl-F", itemFoo->GetItemLabel() );
// These return labels stripped of mnemonics/accelerators:
// wxMenuBar
CPPUNIT_ASSERT_EQUAL( "File", bar->GetMenuLabelText(0) );
// wxMenu
CPPUNIT_ASSERT_EQUAL( "Foo", filemenu->GetLabelText(MenuTestCase_Foo) );
// wxMenuItem
CPPUNIT_ASSERT_EQUAL( "Foo", itemFoo->GetItemLabelText() );
CPPUNIT_ASSERT_EQUAL( "Foo", wxMenuItem::GetLabelText("&Foo\tCtrl-F") );
}
#if wxUSE_INTL
static wxString
GetTranslatedString(const wxTranslations& trans, const wxString& s)
{
const wxString* t = trans.GetTranslatedString(s);
return t ? *t : s;
}
void MenuTestCase::TranslatedMnemonics()
{
// Check that appended mnemonics are correctly stripped;
// see https://github.com/wxWidgets/wxWidgets/issues/16736
wxTranslations trans;
trans.SetLanguage(wxLANGUAGE_JAPANESE);
wxFileTranslationsLoader::AddCatalogLookupPathPrefix("./intl");
CPPUNIT_ASSERT( trans.AddCatalog("internat") );
// Check the translation is being used:
CPPUNIT_ASSERT( wxString("&File") != GetTranslatedString(trans, "&File") );
wxString filemenu = m_frame->GetMenuBar()->GetMenuLabel(0);
CPPUNIT_ASSERT_EQUAL
(
wxStripMenuCodes(GetTranslatedString(trans, "&File"), wxStrip_Menu),
wxStripMenuCodes(GetTranslatedString(trans, filemenu), wxStrip_Menu)
);
// Test strings that have shortcuts. Duplicate non-mnemonic translations
// exist for both "Edit" and "View", for ease of comparison
CPPUNIT_ASSERT_EQUAL
(
GetTranslatedString(trans, "Edit"),
wxStripMenuCodes(GetTranslatedString(trans, "E&dit\tCtrl+E"), wxStrip_Menu)
);
// "Vie&w" also has a space before the (&W)
CPPUNIT_ASSERT_EQUAL
(
GetTranslatedString(trans, "View"),
wxStripMenuCodes(GetTranslatedString(trans, "Vie&w\tCtrl+V"), wxStrip_Menu)
);
// Test a 'normal' mnemonic too: the translation is "Preten&d"
CPPUNIT_ASSERT_EQUAL
(
"Pretend",
wxStripMenuCodes(GetTranslatedString(trans, "B&ogus"), wxStrip_Menu)
);
}
#endif // wxUSE_INTL
void MenuTestCase::RadioItems()
{
wxMenuBar * const bar = m_frame->GetMenuBar();
wxMenu * const menu = new wxMenu;
bar->Append(menu, "&Radio");
// Adding consecutive radio items creates a radio group.
menu->AppendRadioItem(MenuTestCase_First, "Radio 0");
menu->AppendRadioItem(MenuTestCase_First + 1, "Radio 1");
// First item of a radio group is checked by default.
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First) );
// Subsequent items in a group are not checked.
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 1) );
// Checking the second one make the first one unchecked however.
menu->Check(MenuTestCase_First + 1, true);
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First) );
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 1) );
menu->Check(MenuTestCase_First, true);
// Adding more radio items after a separator creates another radio group...
menu->AppendSeparator();
menu->AppendRadioItem(MenuTestCase_First + 2, "Radio 2");
menu->AppendRadioItem(MenuTestCase_First + 3, "Radio 3");
menu->AppendRadioItem(MenuTestCase_First + 4, "Radio 4");
// ... which is independent from the first one.
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First) );
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 2) );
menu->Check(MenuTestCase_First + 3, true);
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 3) );
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 2) );
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First) );
menu->Check(MenuTestCase_First + 2, true);
// Insert an item in the middle of an existing radio group.
menu->InsertRadioItem(4, MenuTestCase_First + 5, "Radio 5");
CPPUNIT_ASSERT( menu->IsChecked(MenuTestCase_First + 2) );
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 5) );
menu->Check( MenuTestCase_First + 5, true );
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 3) );
menu->Check( MenuTestCase_First + 3, true );
// Prepend a couple of items before the first group.
menu->PrependRadioItem(MenuTestCase_First + 6, "Radio 6");
menu->PrependRadioItem(MenuTestCase_First + 7, "Radio 7");
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 6) );
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 7) );
menu->Check(MenuTestCase_First + 7, true);
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 1) );
// Check that the last radio group still works as expected.
menu->Check(MenuTestCase_First + 4, true);
CPPUNIT_ASSERT( !menu->IsChecked(MenuTestCase_First + 5) );
}
void MenuTestCase::RemoveAdd()
{
wxMenuBar* bar = m_frame->GetMenuBar();
wxMenu* menu0 = bar->GetMenu(0);
wxMenu* menu1 = bar->GetMenu(1);
wxMenuItem* item = new wxMenuItem(menu0, MenuTestCase_Foo + 100, "t&ext\tCtrl-E");
menu0->Insert(0, item);
CPPUNIT_ASSERT( menu0->FindItemByPosition(0) == item );
menu0->Remove(item);
CPPUNIT_ASSERT( menu0->FindItemByPosition(0) != item );
menu1->Insert(0, item);
CPPUNIT_ASSERT( menu1->FindItemByPosition(0) == item );
menu1->Remove(item);
CPPUNIT_ASSERT( menu1->FindItemByPosition(0) != item );
menu0->Insert(0, item);
CPPUNIT_ASSERT( menu0->FindItemByPosition(0) == item );
menu0->Delete(item);
}
void MenuTestCase::ChangeBitmap()
{
wxMenu *menu = new wxMenu;
wxMenuItem *item = new wxMenuItem(menu, wxID_ANY, "Item");
menu->Append(item);
// On Windows Vista (and later) calling SetBitmap, *after* the menu
// item has already been added, used to result in a stack overflow:
// [Do]SetBitmap can call GetHBitmapForMenu which will call SetBitmap
// again etc...
item->SetBitmap( wxBitmap(1, 1) );
// Force owner drawn usage by having a bitmap that's wider than the
// standard size. This results in rearranging the parent menu which
// hasn't always worked properly and lead to a null pointer exception.
item->SetBitmap( wxBitmap(512, 1) );
wxDELETE(menu);
}
#if wxUSE_UIACTIONSIMULATOR
// In C++98 this class can't be defined inside Events() method, unfortunately,
// as its OnMenu() method wouldn't be usable with template Bind() then.
class MenuEventHandler : public wxEvtHandler
{
public:
MenuEventHandler(wxWindow* win)
: m_win(win)
{
m_win->Bind(wxEVT_MENU, &MenuEventHandler::OnMenu, this);
m_event = nullptr;
}
virtual ~MenuEventHandler()
{
m_win->Unbind(wxEVT_MENU, &MenuEventHandler::OnMenu, this);
delete m_event;
}
// Check that we received an event with the given ID and return the event
// object if we did (otherwise fail the test and return nullptr).
const wxObject* CheckGot(int expectedId)
{
if ( !m_event )
{
FAIL("Event not generated");
return nullptr;
}
CHECK( m_event->GetId() == expectedId );
const wxObject* const src = m_event->GetEventObject();
delete m_event;
m_event = nullptr;
return src;
}
bool GotEvent() const
{
return m_event != nullptr;
}
private:
void OnMenu(wxCommandEvent& event)
{
CHECK( !m_event );
m_event = static_cast<wxCommandEvent*>(event.Clone());
}
wxWindow* const m_win;
wxCommandEvent* m_event;
};
#endif // wxUSE_UIACTIONSIMULATOR
void MenuTestCase::Events()
{
#if wxUSE_UIACTIONSIMULATOR
MenuEventHandler handler(m_frame);
// Invoke the accelerator.
m_frame->Show();
m_frame->SetFocus();
// Wait for m_frame to become focused. Because (at least under wxQt when running
// the entire test suite) the first test below would fail due to the simulation
// starts before the frame become focused.
WaitFor("the frame to become focused", [this]() {
return m_frame->HasFocus();
});
wxUIActionSimulator sim;
sim.KeyDown(WXK_F1);
sim.KeyUp(WXK_F1);
wxYield();
INFO("Expecting event for F1");
if ( const wxObject* const src = handler.CheckGot(MenuTestCase_Bar) )
{
CHECK( wxString(src->GetClassInfo()->GetClassName()) == "wxMenu" );
CHECK( src == m_menuWithBar );
}
// Invoke another accelerator, it should also work.
sim.Char('A', wxMOD_CONTROL);
wxYield();
INFO("Expecting event for Ctrl-A");
handler.CheckGot(MenuTestCase_SelectAll);
// Invoke accelerator and extra accelerators, all of them should work.
sim.Char('U', wxMOD_CONTROL);
wxYield();
INFO("Expecting event for Ctrl-U");
handler.CheckGot(MenuTestCase_ExtraAccel);
sim.Char('V', wxMOD_CONTROL);
wxYield();
INFO("Expecting event for Ctrl-V");
handler.CheckGot(MenuTestCase_ExtraAccel);
sim.Char('W', wxMOD_CONTROL);
wxYield();
INFO("Expecting event for Ctrl-W");
handler.CheckGot(MenuTestCase_ExtraAccels);
sim.Char('T', wxMOD_CONTROL);
wxYield();
INFO("Expecting event for Ctrl-T");
handler.CheckGot(MenuTestCase_ExtraAccels);
sim.Char('W', wxMOD_CONTROL | wxMOD_SHIFT);
wxYield();
INFO("Expecting event for Ctrl-Shift-W");
handler.CheckGot(MenuTestCase_ExtraAccels);
// Now create a text control which uses the same accelerator for itself and
// check that when the text control has focus, the accelerator does _not_
// work.
wxTextCtrl* const text = new wxTextCtrl(m_frame, wxID_ANY, "Testing");
text->SetFocus();
sim.Char('A', wxMOD_CONTROL);
wxYield();
CHECK( !handler.GotEvent() );
#endif // wxUSE_UIACTIONSIMULATOR
}
namespace
{
void VerifyAccelAssigned( wxString labelText, int keycode )
{
const std::unique_ptr<wxAcceleratorEntry> entry(
wxAcceleratorEntry::Create( labelText )
);
REQUIRE( entry );
CHECK( entry->GetKeyCode() == keycode );
}
struct key
{
int keycode;
wxString name;
bool skip;
};
key modKeys[] =
{
{ wxACCEL_NORMAL, "Normal", false },
{ wxACCEL_CTRL, "Ctrl", false },
{ wxACCEL_SHIFT, "Shift", false },
{ wxACCEL_ALT, "Alt", false }
};
/*
The keys marked as skip below are not supported as accelerator
keys on GTK.
*/
key specialKeys[] =
{
{ WXK_F1, "WXK_F1", false },
{ WXK_F2, "WXK_F2", false },
{ WXK_F3, "WXK_F3", false },
{ WXK_F4, "WXK_F4", false },
{ WXK_F5, "WXK_F5", false },
{ WXK_F6, "WXK_F6", false },
{ WXK_F7, "WXK_F7", false },
{ WXK_F8, "WXK_F8", false },
{ WXK_F9, "WXK_F9", false },
{ WXK_F10, "WXK_F10", false },
{ WXK_F11, "WXK_F11", false },
{ WXK_F12, "WXK_F12", false },
{ WXK_F13, "WXK_F13", false },
{ WXK_F14, "WXK_F14", false },
{ WXK_F15, "WXK_F15", false },
{ WXK_F16, "WXK_F16", false },
{ WXK_F17, "WXK_F17", false },
{ WXK_F18, "WXK_F18", false },
{ WXK_F19, "WXK_F19", false },
{ WXK_F20, "WXK_F20", false },
{ WXK_F21, "WXK_F21", false },
{ WXK_F22, "WXK_F22", false },
{ WXK_F23, "WXK_F23", false },
{ WXK_F24, "WXK_F24", false },
{ WXK_INSERT, "WXK_INSERT", false },
{ WXK_DELETE, "WXK_DELETE", false },
{ WXK_UP, "WXK_UP", false },
{ WXK_DOWN, "WXK_DOWN", false },
{ WXK_PAGEUP, "WXK_PAGEUP", false },
{ WXK_PAGEDOWN, "WXK_PAGEDOWN", false },
{ WXK_LEFT, "WXK_LEFT", false },
{ WXK_RIGHT, "WXK_RIGHT", false },
{ WXK_HOME, "WXK_HOME", false },
{ WXK_END, "WXK_END", false },
{ WXK_RETURN, "WXK_RETURN", false },
{ WXK_BACK, "WXK_BACK", false },
{ WXK_TAB, "WXK_TAB", true },
{ WXK_ESCAPE, "WXK_ESCAPE", false },
{ WXK_SPACE, "WXK_SPACE", false },
{ WXK_MULTIPLY, "WXK_MULTIPLY", false },
{ WXK_ADD, "WXK_ADD", true },
{ WXK_SEPARATOR, "WXK_SEPARATOR", true },
{ WXK_SUBTRACT, "WXK_SUBTRACT", true },
{ WXK_DECIMAL, "WXK_DECIMAL", true },
{ WXK_DIVIDE, "WXK_DIVIDE", true },
{ WXK_CANCEL, "WXK_CANCEL", false },
{ WXK_CLEAR, "WXK_CLEAR", false },
{ WXK_MENU, "WXK_MENU", false },
{ WXK_PAUSE, "WXK_PAUSE", false },
{ WXK_CAPITAL, "WXK_CAPITAL", true },
{ WXK_SELECT, "WXK_SELECT", false },
{ WXK_PRINT, "WXK_PRINT", false },
{ WXK_EXECUTE, "WXK_EXECUTE", false },
{ WXK_SNAPSHOT, "WXK_SNAPSHOT", true },
{ WXK_HELP, "WXK_HELP", false },
{ WXK_NUMLOCK, "WXK_NUMLOCK", true },
{ WXK_SCROLL, "WXK_SCROLL", true },
{ WXK_NUMPAD_INSERT, "WXK_NUMPAD_INSERT", false },
{ WXK_NUMPAD_DELETE, "WXK_NUMPAD_DELETE", false },
{ WXK_NUMPAD_SPACE, "WXK_NUMPAD_SPACE", false },
{ WXK_NUMPAD_TAB, "WXK_NUMPAD_TAB", true },
{ WXK_NUMPAD_ENTER, "WXK_NUMPAD_ENTER", false },
{ WXK_NUMPAD_F1, "WXK_NUMPAD_F1", false },
{ WXK_NUMPAD_F2, "WXK_NUMPAD_F2", false },
{ WXK_NUMPAD_F3, "WXK_NUMPAD_F3", false },
{ WXK_NUMPAD_F4, "WXK_NUMPAD_F4", false },
{ WXK_NUMPAD_HOME, "WXK_NUMPAD_HOME", false },
{ WXK_NUMPAD_LEFT, "WXK_NUMPAD_LEFT", false },
{ WXK_NUMPAD_UP, "WXK_NUMPAD_UP", false },
{ WXK_NUMPAD_RIGHT, "WXK_NUMPAD_RIGHT", false },
{ WXK_NUMPAD_DOWN, "WXK_NUMPAD_DOWN", false },
{ WXK_NUMPAD_PAGEUP, "WXK_NUMPAD_PAGEUP", false },
{ WXK_NUMPAD_PAGEDOWN, "WXK_NUMPAD_PAGEDOWN", false },
{ WXK_NUMPAD_END, "WXK_NUMPAD_END", false },
{ WXK_NUMPAD_BEGIN, "WXK_NUMPAD_BEGIN", false },
{ WXK_NUMPAD_EQUAL, "WXK_NUMPAD_EQUAL", false },
{ WXK_NUMPAD_MULTIPLY, "WXK_NUMPAD_MULTIPLY", false },
{ WXK_NUMPAD_ADD, "WXK_NUMPAD_ADD", false },
{ WXK_NUMPAD_SEPARATOR, "WXK_NUMPAD_SEPARATOR", false },
{ WXK_NUMPAD_SUBTRACT, "WXK_NUMPAD_SUBTRACT", false },
{ WXK_NUMPAD_DECIMAL, "WXK_NUMPAD_DECIMAL", false },
{ WXK_NUMPAD_DIVIDE, "WXK_NUMPAD_DIVIDE", false },
{ WXK_NUMPAD0, "WXK_NUMPAD0", false },
{ WXK_NUMPAD1, "WXK_NUMPAD1", false },
{ WXK_NUMPAD2, "WXK_NUMPAD2", false },
{ WXK_NUMPAD3, "WXK_NUMPAD3", false },
{ WXK_NUMPAD4, "WXK_NUMPAD4", false },
{ WXK_NUMPAD5, "WXK_NUMPAD5", false },
{ WXK_NUMPAD6, "WXK_NUMPAD6", false },
{ WXK_NUMPAD7, "WXK_NUMPAD7", false },
{ WXK_NUMPAD8, "WXK_NUMPAD8", false },
{ WXK_NUMPAD9, "WXK_NUMPAD9", false },
{ WXK_WINDOWS_LEFT, "WXK_WINDOWS_LEFT", true },
{ WXK_WINDOWS_RIGHT, "WXK_WINDOWS_RIGHT", true },
{ WXK_WINDOWS_MENU, "WXK_WINDOWS_MENU", false },
{ WXK_COMMAND, "WXK_COMMAND", true }
};
}
TEST_CASE( "wxMenuItemAccelEntry", "[menu][accelentry]" )
{
wxMenu menu;
menu.Append( wxID_ANY, "Test" );
wxMenuItem* item = menu.FindItemByPosition( 0 );
SECTION( "Modifier keys" )
{
for ( unsigned i = 0; i < WXSIZEOF(modKeys); i++ )
{
const key& k = modKeys[i];
INFO( wxString::Format( "Modifier: %s", k.name ) );
wxAcceleratorEntry accelEntry( k.keycode, 'A' , wxID_ANY, item );
item->SetAccel( &accelEntry );
wxString labelText = item->GetItemLabel();
INFO( wxString::Format( "Label text: %s", labelText ) );
VerifyAccelAssigned( labelText, 'A' );
}
}
SECTION( "Special keys" )
{
for ( unsigned i = 0; i < WXSIZEOF(specialKeys); i++ )
{
const key& k = specialKeys[i];
if( k.skip )
continue;
INFO( wxString::Format( "Keycode: %s", k.name ) );
wxAcceleratorEntry accelEntry( wxACCEL_CTRL, k.keycode, wxID_ANY, item );
item->SetAccel( &accelEntry );
wxString labelText = item->GetItemLabel();
INFO( wxString::Format( "Label text: %s", labelText ) );
VerifyAccelAssigned( labelText, k.keycode );
}
}
}
TEST_CASE("wxMenuItemAccessors", "[menu]")
{
wxMenu menu;
wxMenuItem* const item = menu.AppendCheckItem(wxID_ANY, "Check");
// Just check that we can call various functions.
CHECK( !item->GetBitmapBundle().IsOk() );
CHECK( !item->GetBitmap().IsOk() );
#ifdef __WXMSW__
CHECK( !item->GetBitmapBundle(true).IsOk() );
CHECK( !item->GetBitmap(true).IsOk() );
#endif // __WXMSW__
}
#endif