implemented radio menu items for wxMSW
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@14696 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -5,7 +5,27 @@ selected before the menu goes away (clicking elsewhere dismisses the
|
|||||||
menu). Menus may be used to construct either menu bars or popup menus.
|
menu). Menus may be used to construct either menu bars or popup menus.
|
||||||
|
|
||||||
A menu item has an integer ID associated with it which can be used to
|
A menu item has an integer ID associated with it which can be used to
|
||||||
identify the selection, or to change the menu item in some way.
|
identify the selection, or to change the menu item in some way. A menu item
|
||||||
|
with a special identifier $-1$ is a separator item and doesn't have an
|
||||||
|
associated command but just makes a separator line appear in the menu.
|
||||||
|
|
||||||
|
Menu items may be either normal items, check items or radio items. Normal items
|
||||||
|
don't have any special properties while the check items have a boolean flag
|
||||||
|
associated to them and they show a checkmark in the menu when the flag is set.
|
||||||
|
wxWindows automatically togles the flag value when the item is clicked and its
|
||||||
|
value may be retrieved using either \helpref{IsChecked}{wxmenuischecked} method
|
||||||
|
of wxMenu or wxMenuBar itself or by using
|
||||||
|
\helpref{wxEvent::IsChecked}{wxcommandeventischecked} when you get the menu
|
||||||
|
notification for the item in question.
|
||||||
|
|
||||||
|
The radio items are similar to the check items except that all the other items
|
||||||
|
in the same radio group are unchecked when a radio item is checked. The radio
|
||||||
|
group is formed by a contiguous range of radio items, i.e. it starts at the
|
||||||
|
first item of this kind and ends with the first item of a different kind (or
|
||||||
|
the end of the menu). Notice that because the radio groups are defined in terms
|
||||||
|
of the item positions inserting or removing the items in the menu containing
|
||||||
|
the radio items risks to not work correctly. Finally note that the radio items
|
||||||
|
are only supported under Windows and GTK+ currently.
|
||||||
|
|
||||||
\wxheading{Derived from}
|
\wxheading{Derived from}
|
||||||
|
|
||||||
|
@@ -13,8 +13,8 @@
|
|||||||
#ifndef _WX_FEATURES_H_
|
#ifndef _WX_FEATURES_H_
|
||||||
#define _WX_FEATURES_H_
|
#define _WX_FEATURES_H_
|
||||||
|
|
||||||
// radio menu items are currently only implemented in wxGTK
|
// radio menu items are currently only implemented in wxGTK and wxMSW
|
||||||
#if defined(__WXGTK__) // || defined(__WXMSW__)
|
#if defined(__WXGTK__) || defined(__WXMSW__)
|
||||||
#define wxHAS_RADIO_MENU_ITEMS
|
#define wxHAS_RADIO_MENU_ITEMS
|
||||||
#else
|
#else
|
||||||
#undef wxHAS_RADIO_MENU_ITEMS
|
#undef wxHAS_RADIO_MENU_ITEMS
|
||||||
|
@@ -72,7 +72,8 @@ public:
|
|||||||
wxItemKind GetKind() const { return m_kind; }
|
wxItemKind GetKind() const { return m_kind; }
|
||||||
|
|
||||||
virtual void SetCheckable(bool checkable) { m_kind = wxItem_Check; }
|
virtual void SetCheckable(bool checkable) { m_kind = wxItem_Check; }
|
||||||
bool IsCheckable() const { return m_kind == wxItem_Check; }
|
bool IsCheckable() const
|
||||||
|
{ return m_kind == wxItem_Check || m_kind == wxItem_Radio; }
|
||||||
|
|
||||||
bool IsSubMenu() const { return m_subMenu != NULL; }
|
bool IsSubMenu() const { return m_subMenu != NULL; }
|
||||||
void SetSubMenu(wxMenu *menu) { m_subMenu = menu; }
|
void SetSubMenu(wxMenu *menu) { m_subMenu = menu; }
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
// Name: menu.h
|
// Name: wx/msw/menu.h
|
||||||
// Purpose: wxMenu, wxMenuBar classes
|
// Purpose: wxMenu, wxMenuBar classes
|
||||||
// Author: Julian Smart
|
// Author: Julian Smart
|
||||||
// Modified by: Vadim Zeitlin (wxMenuItem is now in separate file)
|
// Modified by: Vadim Zeitlin (wxMenuItem is now in separate file)
|
||||||
@@ -63,6 +63,8 @@ public:
|
|||||||
// implementation only from now on
|
// implementation only from now on
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
|
|
||||||
|
virtual void Attach(wxMenuBarBase *menubar);
|
||||||
|
|
||||||
bool MSWCommand(WXUINT param, WXWORD id);
|
bool MSWCommand(WXUINT param, WXWORD id);
|
||||||
|
|
||||||
// semi-private accessors
|
// semi-private accessors
|
||||||
@@ -91,9 +93,15 @@ private:
|
|||||||
// common part of Append/Insert (behaves as Append is pos == (size_t)-1)
|
// common part of Append/Insert (behaves as Append is pos == (size_t)-1)
|
||||||
bool DoInsertOrAppend(wxMenuItem *item, size_t pos = (size_t)-1);
|
bool DoInsertOrAppend(wxMenuItem *item, size_t pos = (size_t)-1);
|
||||||
|
|
||||||
|
// terminate the current radio group, if any
|
||||||
|
void EndRadioGroup();
|
||||||
|
|
||||||
// if TRUE, insert a breal before appending the next item
|
// if TRUE, insert a breal before appending the next item
|
||||||
bool m_doBreak;
|
bool m_doBreak;
|
||||||
|
|
||||||
|
// the position of the first item in the current radio group or -1
|
||||||
|
int m_startRadioGroup;
|
||||||
|
|
||||||
// the menu handle of this menu
|
// the menu handle of this menu
|
||||||
WXHMENU m_hMenu;
|
WXHMENU m_hMenu;
|
||||||
|
|
||||||
|
@@ -60,7 +60,19 @@ public:
|
|||||||
// menu handle depending on what we're
|
// menu handle depending on what we're
|
||||||
int GetRealId() const;
|
int GetRealId() const;
|
||||||
|
|
||||||
|
// mark item as belonging to the given radio group
|
||||||
|
void SetRadioGroup(int start, int end)
|
||||||
|
{
|
||||||
|
m_startRadioGroup = start;
|
||||||
|
m_endRadioGroup = end;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// the positions of the first and last items of the radio group this item
|
||||||
|
// belongs to or -1
|
||||||
|
int m_startRadioGroup,
|
||||||
|
m_endRadioGroup;
|
||||||
|
|
||||||
DECLARE_DYNAMIC_CLASS(wxMenuItem)
|
DECLARE_DYNAMIC_CLASS(wxMenuItem)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -196,6 +196,7 @@ bool wxFrameBase::ProcessCommand(int id)
|
|||||||
if (item->IsCheckable())
|
if (item->IsCheckable())
|
||||||
{
|
{
|
||||||
item->Toggle();
|
item->Toggle();
|
||||||
|
|
||||||
// use the new value
|
// use the new value
|
||||||
commandEvent.SetInt(item->IsChecked());
|
commandEvent.SetInt(item->IsChecked());
|
||||||
}
|
}
|
||||||
|
@@ -840,8 +840,13 @@ void wxMenuItem::Check( bool check )
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
wxMenuItemBase::Check( check );
|
wxMenuItemBase::Check( check );
|
||||||
|
|
||||||
|
// GTK+ does it itself for the radio item
|
||||||
|
if ( GetKind() == wxItem_Check )
|
||||||
|
{
|
||||||
gtk_check_menu_item_set_state( (GtkCheckMenuItem*)m_menuItem, (gint)check );
|
gtk_check_menu_item_set_state( (GtkCheckMenuItem*)m_menuItem, (gint)check );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void wxMenuItem::Enable( bool enable )
|
void wxMenuItem::Enable( bool enable )
|
||||||
{
|
{
|
||||||
|
@@ -840,8 +840,13 @@ void wxMenuItem::Check( bool check )
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
wxMenuItemBase::Check( check );
|
wxMenuItemBase::Check( check );
|
||||||
|
|
||||||
|
// GTK+ does it itself for the radio item
|
||||||
|
if ( GetKind() == wxItem_Check )
|
||||||
|
{
|
||||||
gtk_check_menu_item_set_state( (GtkCheckMenuItem*)m_menuItem, (gint)check );
|
gtk_check_menu_item_set_state( (GtkCheckMenuItem*)m_menuItem, (gint)check );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void wxMenuItem::Enable( bool enable )
|
void wxMenuItem::Enable( bool enable )
|
||||||
{
|
{
|
||||||
|
@@ -61,16 +61,31 @@ extern wxMenu *wxCurrentPopupMenu;
|
|||||||
static const int idMenuTitle = -2;
|
static const int idMenuTitle = -2;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// macros
|
// private functions
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
|
// make the given menu item default
|
||||||
IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
|
static void SetDefaultMenuItem(HMENU hmenu, UINT id)
|
||||||
|
{
|
||||||
|
MENUITEMINFO mii;
|
||||||
|
wxZeroMemory(mii);
|
||||||
|
mii.cbSize = sizeof(MENUITEMINFO);
|
||||||
|
mii.fMask = MIIM_STATE;
|
||||||
|
mii.fState = MFS_DEFAULT;
|
||||||
|
|
||||||
|
if ( !::SetMenuItemInfo(hmenu, id, FALSE, &mii) )
|
||||||
|
{
|
||||||
|
wxLogLastError(wxT("SetMenuItemInfo"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// implementation
|
// implementation
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
|
||||||
|
IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// wxMenu construction, adding and removing menu items
|
// wxMenu construction, adding and removing menu items
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -79,6 +94,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
|
|||||||
void wxMenu::Init()
|
void wxMenu::Init()
|
||||||
{
|
{
|
||||||
m_doBreak = FALSE;
|
m_doBreak = FALSE;
|
||||||
|
m_startRadioGroup = -1;
|
||||||
|
|
||||||
// create the menu
|
// create the menu
|
||||||
m_hMenu = (WXHMENU)CreatePopupMenu();
|
m_hMenu = (WXHMENU)CreatePopupMenu();
|
||||||
@@ -121,6 +137,13 @@ void wxMenu::Break()
|
|||||||
m_doBreak = TRUE;
|
m_doBreak = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxMenu::Attach(wxMenuBarBase *menubar)
|
||||||
|
{
|
||||||
|
wxMenuBase::Attach(menubar);
|
||||||
|
|
||||||
|
EndRadioGroup();
|
||||||
|
}
|
||||||
|
|
||||||
#if wxUSE_ACCEL
|
#if wxUSE_ACCEL
|
||||||
|
|
||||||
int wxMenu::FindAccel(int id) const
|
int wxMenu::FindAccel(int id) const
|
||||||
@@ -255,22 +278,13 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
|
|||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// if we just appended the title, highlight it
|
// if we just appended the title, highlight it
|
||||||
#ifdef __WIN32__
|
#ifdef __WIN32__
|
||||||
if ( (int)id == idMenuTitle )
|
if ( (int)id == idMenuTitle )
|
||||||
{
|
{
|
||||||
// visually select the menu title
|
// visually select the menu title
|
||||||
MENUITEMINFO mii;
|
SetDefaultMenuItem(GetHmenu(), id);
|
||||||
mii.cbSize = sizeof(mii);
|
|
||||||
mii.fMask = MIIM_STATE;
|
|
||||||
mii.fState = MFS_DEFAULT;
|
|
||||||
|
|
||||||
if ( !SetMenuItemInfo(GetHmenu(), (unsigned)id, FALSE, &mii) )
|
|
||||||
{
|
|
||||||
wxLogLastError(wxT("SetMenuItemInfo"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // __WIN32__
|
#endif // __WIN32__
|
||||||
|
|
||||||
@@ -282,10 +296,52 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
|
|||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxMenu::EndRadioGroup()
|
||||||
|
{
|
||||||
|
if ( m_startRadioGroup == -1 )
|
||||||
|
{
|
||||||
|
// nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxMenuItemList::Node *nodeStart = GetMenuItems().Item(m_startRadioGroup);
|
||||||
|
wxCHECK_RET( nodeStart, _T("where is the radio group start item?") );
|
||||||
|
|
||||||
|
int endRadioGroup = GetMenuItemCount();
|
||||||
|
|
||||||
|
wxMenuItemList::Node *node = nodeStart;
|
||||||
|
for ( int n = m_startRadioGroup; n < endRadioGroup && node; n++ )
|
||||||
|
{
|
||||||
|
wxMenuItem *item = (wxMenuItem *)node->GetData();
|
||||||
|
item->SetRadioGroup(m_startRadioGroup, endRadioGroup - 1);
|
||||||
|
|
||||||
|
node = node->GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeStart->GetData()->Check(TRUE);
|
||||||
|
|
||||||
|
// we're not inside a radio group any longer
|
||||||
|
m_startRadioGroup = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxMenu::DoAppend(wxMenuItem *item)
|
bool wxMenu::DoAppend(wxMenuItem *item)
|
||||||
{
|
{
|
||||||
|
wxCHECK_MSG( item, FALSE, _T("NULL item in wxMenu::DoAppend") );
|
||||||
|
|
||||||
|
if ( item->GetKind() == wxItem_Radio )
|
||||||
|
{
|
||||||
|
if ( m_startRadioGroup == -1 )
|
||||||
|
{
|
||||||
|
// start a new radio group
|
||||||
|
m_startRadioGroup = GetMenuItemCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // not a radio item
|
||||||
|
{
|
||||||
|
EndRadioGroup();
|
||||||
|
}
|
||||||
|
|
||||||
return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item);
|
return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,15 +465,7 @@ void wxMenu::SetTitle(const wxString& label)
|
|||||||
// put the title string in bold face
|
// put the title string in bold face
|
||||||
if ( !m_title.IsEmpty() )
|
if ( !m_title.IsEmpty() )
|
||||||
{
|
{
|
||||||
MENUITEMINFO mii;
|
SetDefaultMenuItem(GetHmenu(), (UINT)idMenuTitle);
|
||||||
mii.cbSize = sizeof(mii);
|
|
||||||
mii.fMask = MIIM_STATE;
|
|
||||||
mii.fState = MFS_DEFAULT;
|
|
||||||
|
|
||||||
if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
|
|
||||||
{
|
|
||||||
wxLogLastError(wxT("SetMenuItemInfo"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // Win32
|
#endif // Win32
|
||||||
}
|
}
|
||||||
@@ -680,9 +728,6 @@ bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
|
|||||||
if ( !wxMenuBarBase::Append(menu, title) )
|
if ( !wxMenuBarBase::Append(menu, title) )
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
// Already done in Append above
|
|
||||||
//menu->Attach(this);
|
|
||||||
|
|
||||||
m_titles.Add(title);
|
m_titles.Add(title);
|
||||||
|
|
||||||
if ( IsAttached() )
|
if ( IsAttached() )
|
||||||
|
@@ -94,6 +94,9 @@ wxMenuItem::wxMenuItem(wxMenu *pParentMenu,
|
|||||||
{
|
{
|
||||||
wxASSERT_MSG( pParentMenu != NULL, wxT("a menu item should have a parent") );
|
wxASSERT_MSG( pParentMenu != NULL, wxT("a menu item should have a parent") );
|
||||||
|
|
||||||
|
m_startRadioGroup =
|
||||||
|
m_endRadioGroup = -1;
|
||||||
|
|
||||||
#if wxUSE_OWNER_DRAWN
|
#if wxUSE_OWNER_DRAWN
|
||||||
// set default menu colors
|
// set default menu colors
|
||||||
#define SYS_COLOR(c) (wxSystemSettings::GetColour(wxSYS_COLOUR_##c))
|
#define SYS_COLOR(c) (wxSystemSettings::GetColour(wxSYS_COLOUR_##c))
|
||||||
@@ -167,14 +170,58 @@ void wxMenuItem::Check(bool check)
|
|||||||
if ( m_isChecked == check )
|
if ( m_isChecked == check )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
long rc = CheckMenuItem(GetHMenuOf(m_parentMenu),
|
int flags = check ? MF_CHECKED : MF_UNCHECKED;
|
||||||
GetRealId(),
|
HMENU hmenu = GetHMenuOf(m_parentMenu);
|
||||||
MF_BYCOMMAND |
|
|
||||||
(check ? MF_CHECKED : MF_UNCHECKED));
|
|
||||||
|
|
||||||
if ( rc == -1 ) {
|
if ( GetKind() == wxItem_Radio )
|
||||||
|
{
|
||||||
|
// it doesn't make sense to uncheck a radio item - what would this do?
|
||||||
|
if ( !check )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const wxMenuItemList& items = m_parentMenu->GetMenuItems();
|
||||||
|
int pos = items.IndexOf(this);
|
||||||
|
wxCHECK_RET( pos != wxNOT_FOUND,
|
||||||
|
_T("menuitem not found in the menu items list?") );
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
if ( !::CheckMenuRadioItem(hmenu,
|
||||||
|
m_startRadioGroup, // first group item
|
||||||
|
m_endRadioGroup, // last one
|
||||||
|
pos, // the one to check
|
||||||
|
MF_BYPOSITION | flags) )
|
||||||
|
{
|
||||||
|
wxLogLastError(_T("CheckMenuRadioItem"));
|
||||||
|
}
|
||||||
|
#endif // __WIN32__
|
||||||
|
|
||||||
|
// also uncheck all the other items in this radio group
|
||||||
|
wxMenuItemList::Node *node = items.Item(m_startRadioGroup);
|
||||||
|
for ( int n = m_startRadioGroup; n <= m_endRadioGroup && node; n++ )
|
||||||
|
{
|
||||||
|
if ( n != pos )
|
||||||
|
{
|
||||||
|
node->GetData()->m_isChecked = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we also have to do it in the menu for Win16 (under Win32
|
||||||
|
// CheckMenuRadioItem() does it for us)
|
||||||
|
#ifndef __WIN32__
|
||||||
|
::CheckMenuItem(hmenu, n, n == pos ? MF_CHECKED : MF_UNCHECKED);
|
||||||
|
#endif // Win16
|
||||||
|
|
||||||
|
node = node->GetNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // check item
|
||||||
|
{
|
||||||
|
if ( ::CheckMenuItem(hmenu,
|
||||||
|
GetRealId(),
|
||||||
|
MF_BYCOMMAND | flags) == -1 )
|
||||||
|
{
|
||||||
wxLogLastError(wxT("CheckMenuItem"));
|
wxLogLastError(wxT("CheckMenuItem"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wxMenuItemBase::Check(check);
|
wxMenuItemBase::Check(check);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user