From 974e8d946f30af2bd79b9029d1d2fb9e0d5b2dd4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 25 Oct 1999 15:51:37 +0000 Subject: [PATCH] 1. small dnd compilation fixes (no attempt to make icon setting work though) 2. wxMenuItemBase appears 3. more key combinations handled by wxGTK for menu accels git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4184 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/dnd.h | 1 + include/wx/gtk/menu.h | 6 -- include/wx/gtk/menuitem.h | 82 ++++------------ include/wx/gtk1/menu.h | 6 -- include/wx/gtk1/menuitem.h | 82 ++++------------ include/wx/menuitem.h | 115 ++++++++++++++++++++-- include/wx/msw/menu.h | 12 ++- include/wx/msw/menuitem.h | 95 +++++++----------- include/wx/ownerdrw.h | 28 +++--- include/wx/utils.h | 7 +- src/common/utilscmn.cpp | 93 +++++++++++++++++- src/gtk/dnd.cpp | 2 +- src/gtk/menu.cpp | 192 ++++++++++++++++++++++--------------- src/gtk1/dnd.cpp | 2 +- src/gtk1/menu.cpp | 192 ++++++++++++++++++++++--------------- src/msw/menu.cpp | 98 +++---------------- src/msw/menuitem.cpp | 110 ++++++++++++--------- 17 files changed, 619 insertions(+), 504 deletions(-) diff --git a/include/wx/dnd.h b/include/wx/dnd.h index 0d113904ec..6233f1525a 100644 --- a/include/wx/dnd.h +++ b/include/wx/dnd.h @@ -17,6 +17,7 @@ #if wxUSE_DRAG_AND_DROP #include "wx/dataobj.h" +#include "wx/cursor.h" // ---------------------------------------------------------------------------- // constants diff --git a/include/wx/gtk/menu.h b/include/wx/gtk/menu.h index dfa0569718..9d4b13d2d0 100644 --- a/include/wx/gtk/menu.h +++ b/include/wx/gtk/menu.h @@ -29,12 +29,6 @@ class wxMenuBar; class wxMenuItem; class wxMenu; -//----------------------------------------------------------------------------- -// const -//----------------------------------------------------------------------------- - -#define ID_SEPARATOR (-1) - //----------------------------------------------------------------------------- // wxMenuBar //----------------------------------------------------------------------------- diff --git a/include/wx/gtk/menuitem.h b/include/wx/gtk/menuitem.h index 500e235d68..8152ab4d6a 100644 --- a/include/wx/gtk/menuitem.h +++ b/include/wx/gtk/menuitem.h @@ -14,83 +14,43 @@ #pragma interface #endif -#include "wx/defs.h" -#include "wx/string.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -#define ID_SEPARATOR (-1) - -//----------------------------------------------------------------------------- -// classes -//----------------------------------------------------------------------------- - -class wxMenuItem; -class wxMenu; - //----------------------------------------------------------------------------- // wxMenuItem //----------------------------------------------------------------------------- -class wxMenuItem : public wxObject +class wxMenuItem : public wxMenuItemBase { -DECLARE_DYNAMIC_CLASS(wxMenuItem) - public: - wxMenuItem(); + wxMenuItem(wxMenu *parentMenu = (wxMenu *)NULL, + int id = wxID_SEPARATOR, + const wxString& text = wxEmptyString, + const wxString& help = wxEmptyString, + bool isCheckable = FALSE, + wxMenu *subMenu = (wxMenu *)NULL); ~wxMenuItem(); - // accessors - // id - void SetId(int id) { m_id = id; } - int GetId() const { return m_id; } - bool IsSeparator() const { return m_id == ID_SEPARATOR; } - - // the item's text = name - void SetName(const wxString& str); - void SetText(const wxString& str) { SetName(str); } // compatibility - const wxString& GetName() const { return m_text; } - const wxString& GetText() const { return GetName(); } - - // what kind of menu item we are - void SetCheckable(bool checkable) { m_isCheckMenu = checkable; } - bool IsCheckable() const { return m_isCheckMenu; } - void SetSubMenu(wxMenu *menu) { m_subMenu = menu; } - wxMenu *GetSubMenu() const { return m_subMenu; } - bool IsSubMenu() const { return m_subMenu != NULL; } - - // state - void Enable( bool enable = TRUE ); - bool IsEnabled() const { return m_isEnabled; } - void Check( bool check = TRUE ); - bool IsChecked() const; - - // help string (displayed in the status bar by default) - void SetHelp(const wxString& str) { m_helpStr = str; } - const wxString& GetHelp() const { return m_helpStr; } + // implement base class virtuals + virtual void SetText( const wxString& str ) { DoSetText(str); } + virtual void Enable( bool enable = TRUE ); + virtual void Check( bool check = TRUE ); + virtual bool IsChecked() const; // implementation void SetMenuItem(GtkWidget *menuItem) { m_menuItem = menuItem; } GtkWidget *GetMenuItem() const { return m_menuItem; } - - wxString GetHotKey() const { return m_hotKey; } - void SetCheckedFlag(bool checked) { m_isChecked = checked; } - bool GetCheckedFlag() const { return m_isChecked; } + wxString GetHotKey() const { return m_hotKey; } private: - int m_id; - wxString m_text; - wxString m_hotKey; - bool m_isCheckMenu; - bool m_isChecked; - bool m_isEnabled; - wxMenu *m_subMenu; - wxString m_helpStr; + // DoSetText() transforms the accel mnemonics in our label from MSW/wxWin + // style to GTK+ and is called from ctor and SetText() + void DoSetText(const wxString& text); + + wxString m_hotKey; + + GtkWidget *m_menuItem; // GtkMenuItem - GtkWidget *m_menuItem; // GtkMenuItem + DECLARE_DYNAMIC_CLASS(wxMenuItem) }; diff --git a/include/wx/gtk1/menu.h b/include/wx/gtk1/menu.h index dfa0569718..9d4b13d2d0 100644 --- a/include/wx/gtk1/menu.h +++ b/include/wx/gtk1/menu.h @@ -29,12 +29,6 @@ class wxMenuBar; class wxMenuItem; class wxMenu; -//----------------------------------------------------------------------------- -// const -//----------------------------------------------------------------------------- - -#define ID_SEPARATOR (-1) - //----------------------------------------------------------------------------- // wxMenuBar //----------------------------------------------------------------------------- diff --git a/include/wx/gtk1/menuitem.h b/include/wx/gtk1/menuitem.h index 500e235d68..8152ab4d6a 100644 --- a/include/wx/gtk1/menuitem.h +++ b/include/wx/gtk1/menuitem.h @@ -14,83 +14,43 @@ #pragma interface #endif -#include "wx/defs.h" -#include "wx/string.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -#define ID_SEPARATOR (-1) - -//----------------------------------------------------------------------------- -// classes -//----------------------------------------------------------------------------- - -class wxMenuItem; -class wxMenu; - //----------------------------------------------------------------------------- // wxMenuItem //----------------------------------------------------------------------------- -class wxMenuItem : public wxObject +class wxMenuItem : public wxMenuItemBase { -DECLARE_DYNAMIC_CLASS(wxMenuItem) - public: - wxMenuItem(); + wxMenuItem(wxMenu *parentMenu = (wxMenu *)NULL, + int id = wxID_SEPARATOR, + const wxString& text = wxEmptyString, + const wxString& help = wxEmptyString, + bool isCheckable = FALSE, + wxMenu *subMenu = (wxMenu *)NULL); ~wxMenuItem(); - // accessors - // id - void SetId(int id) { m_id = id; } - int GetId() const { return m_id; } - bool IsSeparator() const { return m_id == ID_SEPARATOR; } - - // the item's text = name - void SetName(const wxString& str); - void SetText(const wxString& str) { SetName(str); } // compatibility - const wxString& GetName() const { return m_text; } - const wxString& GetText() const { return GetName(); } - - // what kind of menu item we are - void SetCheckable(bool checkable) { m_isCheckMenu = checkable; } - bool IsCheckable() const { return m_isCheckMenu; } - void SetSubMenu(wxMenu *menu) { m_subMenu = menu; } - wxMenu *GetSubMenu() const { return m_subMenu; } - bool IsSubMenu() const { return m_subMenu != NULL; } - - // state - void Enable( bool enable = TRUE ); - bool IsEnabled() const { return m_isEnabled; } - void Check( bool check = TRUE ); - bool IsChecked() const; - - // help string (displayed in the status bar by default) - void SetHelp(const wxString& str) { m_helpStr = str; } - const wxString& GetHelp() const { return m_helpStr; } + // implement base class virtuals + virtual void SetText( const wxString& str ) { DoSetText(str); } + virtual void Enable( bool enable = TRUE ); + virtual void Check( bool check = TRUE ); + virtual bool IsChecked() const; // implementation void SetMenuItem(GtkWidget *menuItem) { m_menuItem = menuItem; } GtkWidget *GetMenuItem() const { return m_menuItem; } - - wxString GetHotKey() const { return m_hotKey; } - void SetCheckedFlag(bool checked) { m_isChecked = checked; } - bool GetCheckedFlag() const { return m_isChecked; } + wxString GetHotKey() const { return m_hotKey; } private: - int m_id; - wxString m_text; - wxString m_hotKey; - bool m_isCheckMenu; - bool m_isChecked; - bool m_isEnabled; - wxMenu *m_subMenu; - wxString m_helpStr; + // DoSetText() transforms the accel mnemonics in our label from MSW/wxWin + // style to GTK+ and is called from ctor and SetText() + void DoSetText(const wxString& text); + + wxString m_hotKey; + + GtkWidget *m_menuItem; // GtkMenuItem - GtkWidget *m_menuItem; // GtkMenuItem + DECLARE_DYNAMIC_CLASS(wxMenuItem) }; diff --git a/include/wx/menuitem.h b/include/wx/menuitem.h index c19c785ffe..ea5ac56053 100644 --- a/include/wx/menuitem.h +++ b/include/wx/menuitem.h @@ -1,21 +1,122 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/menuitem.h +// Purpose: wxMenuItem class +// Author: Vadim Zeitlin +// Modified by: +// Created: 25.10.99 +// RCS-ID: $Id$ +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + #ifndef _WX_MENUITEM_H_BASE_ #define _WX_MENUITEM_H_BASE_ +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/object.h" // base class + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// id for a separator line in the menu (invalid for normal item) +#define wxID_SEPARATOR (-1) + +#ifndef ID_SEPARATOR // for compatibility only, don't use in new code + #define ID_SEPARATOR wxID_SEPARATOR +#endif + +// ---------------------------------------------------------------------------- +// forward declarations +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxMenuItem; +class WXDLLEXPORT wxMenu; + +// ---------------------------------------------------------------------------- +// wxMenuItem is an item in the menu which may be either a normal item, a sub +// menu or a separator +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxMenuItemBase : public wxObject +{ +public: + // creation + static wxMenuItem *New(wxMenu *parentMenu = (wxMenu *)NULL, + int id = wxID_SEPARATOR, + const wxString& text = wxEmptyString, + const wxString& help = wxEmptyString, + bool isCheckable = FALSE, + wxMenu *subMenu = (wxMenu *)NULL); + + // get/set id + void SetId(int id) { m_id = id; } + int GetId() const { return m_id; } + bool IsSeparator() const { return m_id == wxID_SEPARATOR; } + + // the item's text (or name, or label...) + virtual void SetText(const wxString& str) { m_text = str; } + const wxString& GetText() const { return m_text; } + + // what kind of menu item we are + virtual void SetCheckable(bool checkable) { m_isCheckable = checkable; } + bool IsCheckable() const { return m_isCheckable; } + + bool IsSubMenu() const { return m_subMenu != NULL; } + void SetSubMenu(wxMenu *menu) { m_subMenu = menu; } + wxMenu *GetSubMenu() const { return m_subMenu; } + + // state + virtual void Enable(bool enable = TRUE) { m_isEnabled = enable; } + virtual bool IsEnabled() const { return m_isEnabled; } + virtual void Check(bool check = TRUE) { m_isChecked = check; } + virtual bool IsChecked() const { return m_isChecked; } + + // help string (displayed in the status bar by default) + void SetHelp(const wxString& str) { m_help = str; } + const wxString& GetHelp() const { return m_help; } + + // compatibility only, use new functions in the new code + void SetName(const wxString& str) { SetText(str); } + const wxString& GetName() const { return GetText(); } + +protected: + int m_id; // numeric id of the item >= 0 or -1 + wxMenu *m_parentMenu, // the menu we belong to + *m_subMenu; // our sub menu or NULL + wxString m_text, // label of the item + m_help; // the help string for the item + bool m_isCheckable; // can be checked? + bool m_isChecked; // is checked? + bool m_isEnabled; // is enabled? +}; + +// ---------------------------------------------------------------------------- +// include the real class declaration +// ---------------------------------------------------------------------------- + +#ifdef wxUSE_BASE_CLASSES_ONLY + #define wxMenuItem wxMenuItemBase +#else // !wxUSE_BASE_CLASSES_ONLY #if defined(__WXMSW__) -#include "wx/msw/menuitem.h" + #include "wx/msw/menuitem.h" #elif defined(__WXMOTIF__) -#include "wx/motif/menuitem.h" + #include "wx/motif/menuitem.h" #elif defined(__WXGTK__) -#include "wx/gtk/menuitem.h" + #include "wx/gtk/menuitem.h" #elif defined(__WXQT__) -#include "wx/qt/menuitem.h" + #include "wx/qt/menuitem.h" #elif defined(__WXMAC__) -#include "wx/mac/menuitem.h" + #include "wx/mac/menuitem.h" #elif defined(__WXPM__) -#include "wx/os2/menuitem.h" + #include "wx/os2/menuitem.h" #elif defined(__WXSTUBS__) -#include "wx/stubs/menuitem.h" + #include "wx/stubs/menuitem.h" #endif +#endif // wxUSE_BASE_CLASSES_ONLY/!wxUSE_BASE_CLASSES_ONLY #endif // _WX_MENUITEM_H_BASE_ diff --git a/include/wx/msw/menu.h b/include/wx/msw/menu.h index 9d2ca80bd8..e8fed5225a 100644 --- a/include/wx/msw/menu.h +++ b/include/wx/msw/menu.h @@ -22,7 +22,7 @@ #include "wx/string.h" #if wxUSE_ACCEL -#include "wx/accel.h" + #include "wx/accel.h" #endif // wxUSE_ACCEL class WXDLLEXPORT wxMenuItem; @@ -32,6 +32,8 @@ class WXDLLEXPORT wxFrame; WXDLLEXPORT_DATA(extern const wxChar*) wxEmptyString; +WX_DEFINE_ARRAY(wxAcceleratorEntry *, wxAcceleratorArray); + // ---------------------------------------------------------------------------- // Menu // ---------------------------------------------------------------------------- @@ -50,7 +52,7 @@ public: wxMenu( long WXUNUSED(style) ) { - Init( wxEmptyString ); + Init( wxEmptyString ); } wxMenu(const wxString& title = wxEmptyString, long WXUNUSED(style) = 0) @@ -147,7 +149,7 @@ public: void Detach(); #if wxUSE_ACCEL - size_t GetAccelCount() const { return m_accelKeyCodes.GetCount(); } + size_t GetAccelCount() const { return m_accels.GetCount(); } size_t CopyAccels(wxAcceleratorEntry *accels) const; #endif // wxUSE_ACCEL @@ -186,8 +188,8 @@ private: void* m_clientData; #if wxUSE_ACCEL - // the accelerators data - wxArrayInt m_accelKeyCodes, m_accelFlags, m_accelIds; + // the accelerators for our menu items + wxAcceleratorArray m_accels; #endif // wxUSE_ACCEL }; diff --git a/include/wx/msw/menuitem.h b/include/wx/msw/menuitem.h index 28e8e1c9db..aa26ee2158 100644 --- a/include/wx/msw/menuitem.h +++ b/include/wx/msw/menuitem.h @@ -20,81 +20,50 @@ // headers // ---------------------------------------------------------------------------- -#include "wx/setup.h" - -// an exception to the general rule that a normal header doesn't include other -// headers - only because ownerdrw.h is not always included and I don't want -// to write #ifdef's everywhere... #if wxUSE_OWNER_DRAWN - #include "wx/ownerdrw.h" + #include "wx/ownerdrw.h" // base class #endif -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// id for a separator line in the menu (invalid for normal item) -#define ID_SEPARATOR (-1) - // ---------------------------------------------------------------------------- // wxMenuItem: an item in the menu, optionally implements owner-drawn behaviour // ---------------------------------------------------------------------------- -class WXDLLEXPORT wxMenuItem: public wxObject + +class WXDLLEXPORT wxMenuItem : public wxMenuItemBase #if wxUSE_OWNER_DRAWN - , public wxOwnerDrawn + , public wxOwnerDrawn #endif { -DECLARE_DYNAMIC_CLASS(wxMenuItem) - public: - // ctor & dtor - wxMenuItem(wxMenu *pParentMenu = NULL, int id = ID_SEPARATOR, - const wxString& strName = "", const wxString& wxHelp = "", - bool bCheckable = FALSE, wxMenu *pSubMenu = NULL); - virtual ~wxMenuItem(); - - // accessors (some more are inherited from wxOwnerDrawn or are below) - bool IsSeparator() const { return m_idItem == ID_SEPARATOR; } - bool IsEnabled() const { return m_bEnabled; } - bool IsChecked() const { return m_bChecked; } - bool IsSubMenu() const { return GetSubMenu() != NULL; } - - int GetId() const { return m_idItem; } - const wxString& GetHelp() const { return m_strHelp; } - wxMenu *GetSubMenu() const { return m_pSubMenu; } - - // the id for a popup menu is really its menu handle (as required by - // ::AppendMenu() API) - int GetRealId() const; - - // operations - void SetName(const wxString& strName); - void SetHelp(const wxString& strHelp) { m_strHelp = strHelp; } - - void Enable(bool bDoEnable = TRUE); - void Check(bool bDoCheck = TRUE); - - void DeleteSubMenu(); + // ctor & dtor + wxMenuItem(wxMenu *parentMenu = (wxMenu *)NULL, + int id = wxID_SEPARATOR, + const wxString& name = wxEmptyString, + const wxString& help = wxEmptyString, + bool isCheckable = FALSE, + wxMenu *subMenu = (wxMenu *)NULL); + virtual ~wxMenuItem(); + + // override base class virtuals + virtual void SetText(const wxString& strName); + virtual void SetCheckable(bool checkable); + + virtual void Enable(bool bDoEnable = TRUE); + virtual void Check(bool bDoCheck = TRUE); + + // unfortunately needed to resolve ambiguity between + // wxMenuItemBase::IsCheckable() and wxOwnerDrawn::IsCheckable() + bool IsCheckable() const { return wxMenuItemBase::IsCheckable(); } + + // the id for a popup menu is really its menu handle (as required by + // ::AppendMenu() API), so this function will return either the id or the + // menu handle depending on what we're + int GetRealId() const; + + // delete the submenu + void DeleteSubMenu(); private: - int m_idItem; // numeric id of the item - wxString m_strHelp; // associated help string - wxMenu *m_pSubMenu, // may be NULL - *m_pParentMenu; // menu this item is contained in - bool m_bEnabled, // enabled or greyed? - m_bChecked; // checked? (only if checkable) - -#if wxUSE_OWNER_DRAWN - // wxOwnerDrawn base class already has these variables - nothing to do - -#else //!owner drawn - bool m_bCheckable; // can be checked? - wxString m_strName; // name or label of the item - -public: - const wxString& GetName() const { return m_strName; } - bool IsCheckable() const { return m_bCheckable; } -#endif //owner drawn + DECLARE_DYNAMIC_CLASS(wxMenuItem) }; #endif //_MENUITEM_H diff --git a/include/wx/ownerdrw.h b/include/wx/ownerdrw.h index e92483cc61..3008d453a8 100644 --- a/include/wx/ownerdrw.h +++ b/include/wx/ownerdrw.h @@ -12,12 +12,14 @@ #ifndef _OWNERDRW_H #define _OWNERDRW_H +#include "wx/setup.h" + +#if wxUSE_OWNER_DRAWN + #ifdef __GNUG__ -#pragma interface "ownerdrw.h" + #pragma interface "ownerdrw.h" #endif -#include - // ---------------------------------------------------------------------------- // wxOwnerDrawn - a mix-in base class, derive from it to implement owner-drawn // behaviour @@ -26,11 +28,12 @@ // also supports 3 bitmaps: either a checked/unchecked bitmap for a checkable // element or one unchangeable bitmap otherwise. // ---------------------------------------------------------------------------- + class WXDLLEXPORT wxOwnerDrawn { public: // ctor & dtor - wxOwnerDrawn(const wxString& str = "", + wxOwnerDrawn(const wxString& str = wxEmptyString, bool bCheckable = FALSE, bool bMenuItem = FALSE); // FIXME kludge for colors virtual ~wxOwnerDrawn() { } @@ -78,17 +81,18 @@ public: static int GetDefaultMarginWidth() { return (int) ms_nDefaultMarginWidth; } // accessors - void SetName(const wxString& strName) { m_strName = strName; } - const wxString& GetName() const { return m_strName; } - bool IsCheckable() const { return m_bCheckable; } + void SetName(const wxString& strName) { m_strName = strName; } + const wxString& GetName() const { return m_strName; } + void SetCheckable(bool checkable) { m_bCheckable = checkable; } + bool IsCheckable() const { return m_bCheckable; } // this function might seem strange, but if it returns FALSE it means that // no non-standard attribute are set, so there is no need for this control // to be owner-drawn. Moreover, you can force owner-drawn to FALSE if you // want to change, say, the color for the item but only if it is owner-drawn // (see wxMenuItem::wxMenuItem for example) - bool IsOwnerDrawn() const { return m_bOwnerDrawn; } - void ResetOwnerDrawn() { m_bOwnerDrawn = FALSE; } + bool IsOwnerDrawn() const { return m_bOwnerDrawn; } + void ResetOwnerDrawn() { m_bOwnerDrawn = FALSE; } public: // constants used in OnDrawItem @@ -125,14 +129,16 @@ private: m_bOwnerDrawn; // true if something is non standard wxFont m_font; // font to use for drawing - wxColour m_colText, // color ----"---"---"---- + wxColour m_colText, // color ----"---"---"---- m_colBack; // background color wxBitmap m_bmpChecked, // bitmap to put near the item m_bmpUnchecked; // (checked is used also for 'uncheckable' items) - size_t m_nHeight, // font height + size_t m_nHeight, // font height m_nMarginWidth; // space occupied by bitmap to the left of the item }; +#endif // wxUSE_OWNER_DRAWN + #endif // _OWNERDRW_H diff --git a/include/wx/utils.h b/include/wx/utils.h index 9e964e7a3d..35b2496ab9 100644 --- a/include/wx/utils.h +++ b/include/wx/utils.h @@ -221,12 +221,17 @@ WXDLLEXPORT wxChar* wxGetUserHome(const wxString& user = wxEmptyString); #if wxUSE_GUI // GUI only things from now on // ---------------------------------------------------------------------------- -// Strip out any menu codes +// Menu accelerators related things // ---------------------------------------------------------------------------- WXDLLEXPORT wxChar* wxStripMenuCodes(wxChar *in, wxChar *out = (wxChar *) NULL); WXDLLEXPORT wxString wxStripMenuCodes(const wxString& str); +#if wxUSE_ACCEL +class WXDLLEXPORT wxAcceleratorEntry; +WXDLLEXPORT wxAcceleratorEntry *wxGetAccelFromString(const wxString& label); +#endif // wxUSE_ACCEL + // ---------------------------------------------------------------------------- // Window search // ---------------------------------------------------------------------------- diff --git a/src/common/utilscmn.cpp b/src/common/utilscmn.cpp index 1fcc2b7346..2491395090 100644 --- a/src/common/utilscmn.cpp +++ b/src/common/utilscmn.cpp @@ -32,6 +32,8 @@ #include "wx/defs.h" #include "wx/string.h" #include "wx/utils.h" + #include "wx/intl.h" + #include "wx/log.h" #if wxUSE_GUI #include "wx/window.h" @@ -39,6 +41,10 @@ #include "wx/frame.h" #include "wx/msgdlg.h" #include "wx/textdlg.h" + #if wxUSE_ACCEL + #include "wx/menuitem.h" + #include "wx/accel.h" + #endif // wxUSE_ACCEL #endif // wxUSE_GUI #endif // WX_PRECOMP @@ -392,7 +398,7 @@ wxString wxNow() #if wxUSE_GUI // ---------------------------------------------------------------------------- -// Strip out any menu codes +// Menu accelerators related functions // ---------------------------------------------------------------------------- wxChar *wxStripMenuCodes (wxChar *in, wxChar *out) @@ -439,6 +445,91 @@ wxString wxStripMenuCodes(const wxString& str) return str1; } +#if wxUSE_ACCEL + +// return wxAcceleratorEntry for the given menu string or NULL if none +// specified +wxAcceleratorEntry *wxGetAccelFromString(const wxString& label) +{ + // check for accelerators: they are given after '\t' + int posTab = label.Find(wxT('\t')); + if ( posTab != wxNOT_FOUND ) { + // parse the accelerator string + int keyCode = 0; + int accelFlags = wxACCEL_NORMAL; + wxString current; + for ( size_t n = (size_t)posTab + 1; n < label.Len(); n++ ) { + if ( (label[n] == '+') || (label[n] == '-') ) { + if ( current == _("ctrl") ) + accelFlags |= wxACCEL_CTRL; + else if ( current == _("alt") ) + accelFlags |= wxACCEL_ALT; + else if ( current == _("shift") ) + accelFlags |= wxACCEL_SHIFT; + else { + wxLogDebug(wxT("Unknown accel modifier: '%s'"), + current.c_str()); + } + + current.Empty(); + } + else { + current += wxTolower(label[n]); + } + } + + if ( current.IsEmpty() ) { + wxLogDebug(wxT("No accel key found, accel string ignored.")); + } + else { + if ( current.Len() == 1 ) { + // it's a letter + keyCode = wxToupper(current[0U]); + } + else { + // is it a function key? + if ( current[0U] == 'f' && isdigit(current[1U]) && + (current.Len() == 2 || + (current.Len() == 3 && isdigit(current[2U]))) ) { + int n; + wxSscanf(current.c_str() + 1, wxT("%d"), &n); + + keyCode = WXK_F1 + n - 1; + } + else { +#if 0 // this is not supported by GTK+, apparently + // several special cases + current.MakeUpper(); + if ( current == wxT("DEL") ) { + keyCode = VK_DELETE; + } + else if ( current == wxT("PGUP") ) { + keyCode = VK_PRIOR; + } + else if ( current == wxT("PGDN") ) { + keyCode = VK_NEXT; + } + else +#endif // 0 + { + wxLogDebug(wxT("Unrecognized accel key '%s', accel " + "string ignored."), current.c_str()); + } + } + } + } + + if ( keyCode ) { + // we do have something + return new wxAcceleratorEntry(accelFlags, keyCode); + } + } + + return NULL; +} + +#endif // wxUSE_ACCEL + // ---------------------------------------------------------------------------- // Window search functions // ---------------------------------------------------------------------------- diff --git a/src/gtk/dnd.cpp b/src/gtk/dnd.cpp index fbd0ec5b86..fdd1f25e8f 100644 --- a/src/gtk/dnd.cpp +++ b/src/gtk/dnd.cpp @@ -628,7 +628,7 @@ gtk_dnd_window_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigur if (source->m_dragContext->action == GDK_ACTION_COPY) action = wxDragCopy; if (source->m_dragContext->action == GDK_ACTION_MOVE) action = wxDragMove; - source->GiveFeedback( action, FALSE ); + source->GiveFeedback( action ); return 0; } diff --git a/src/gtk/menu.cpp b/src/gtk/menu.cpp index 35a6a05cd0..de0b18636f 100644 --- a/src/gtk/menu.cpp +++ b/src/gtk/menu.cpp @@ -17,6 +17,10 @@ #include "wx/intl.h" #include "wx/app.h" +#if wxUSE_ACCEL + #include "wx/accel.h" +#endif // wxUSE_ACCEL + #include "gdk/gdk.h" #include "gtk/gtk.h" @@ -85,7 +89,7 @@ wxMenuBar::wxMenuBar() wxFAIL_MSG( wxT("wxMenuBar creation failed") ); return; } - + m_menus.DeleteContents( TRUE ); /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ @@ -113,7 +117,7 @@ static void wxMenubarUnsetInvokingWindow( wxMenu *menu, wxWindow *win ) #if (GTK_MINOR_VERSION > 0) wxWindow *top_frame = win; - while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) + while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) top_frame = top_frame->GetParent(); /* support for native hot keys */ @@ -136,7 +140,7 @@ static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win ) #if (GTK_MINOR_VERSION > 0) wxWindow *top_frame = win; - while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) + while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) top_frame = top_frame->GetParent(); /* support for native hot keys */ @@ -158,7 +162,7 @@ void wxMenuBar::SetInvokingWindow( wxWindow *win ) m_invokingWindow = win; #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) wxWindow *top_frame = win; - while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) + while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) top_frame = top_frame->GetParent(); /* support for native key accelerators indicated by underscroes */ @@ -179,7 +183,7 @@ void wxMenuBar::UnsetInvokingWindow( wxWindow *win ) m_invokingWindow = (wxWindow*) NULL; #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) wxWindow *top_frame = win; - while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) + while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) top_frame = top_frame->GetParent(); /* support for native key accelerators indicated by underscroes */ @@ -257,7 +261,7 @@ void wxMenuBar::Append( wxMenu *menu, const wxString &title ) { // contrary to the common sense, we must throw out _all_ underscores, // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we - // might naively think). IMHO it's a bug in GTK+ (VZ) + // might naively think). IMHO it's a bug in GTK+ (VZ) while (*pc == wxT('_')) pc++; tmp << *pc; @@ -488,15 +492,17 @@ static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu ) if (item->IsCheckable()) { - if (item->GetCheckedFlag() == item->IsChecked()) + bool isReallyChecked = item->IsChecked(); + if ( item->wxMenuItemBase::IsChecked() == isReallyChecked ) { /* the menu item has been checked by calling wxMenuItem->Check() */ return; } else { - /* the user pressed on the menu item -> report */ - item->SetCheckedFlag(item->IsChecked()); /* make consistent again */ + /* the user pressed on the menu item -> report and make consistent + * again */ + item->wxMenuItemBase::Check(isReallyChecked); } } @@ -573,16 +579,37 @@ static void gtk_menu_nolight_callback( GtkWidget *widget, wxMenu *menu ) // wxMenuItem //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxMenuItem,wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxMenuItemBase) + +wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu, + int id, + const wxString& name, + const wxString& help, + bool isCheckable, + wxMenu *subMenu) +{ + return new wxMenuItem(parentMenu, id, name, help, isCheckable, subMenu); +} -wxMenuItem::wxMenuItem() +wxMenuItem::wxMenuItem(wxMenu *parentMenu, + int id, + const wxString& text, + const wxString& help, + bool isCheckable, + wxMenu *subMenu) { - m_id = ID_SEPARATOR; - m_isCheckMenu = FALSE; + m_id = id; + m_isCheckable = isCheckable; m_isChecked = FALSE; m_isEnabled = TRUE; - m_subMenu = (wxMenu *) NULL; + m_subMenu = subMenu; + m_parentMenu = parentMenu; + m_help = help; + m_menuItem = (GtkWidget *) NULL; + + // call it after initializing m_menuItem to NULL + DoSetText(text); } wxMenuItem::~wxMenuItem() @@ -591,10 +618,10 @@ wxMenuItem::~wxMenuItem() } // it's valid for this function to be called even if m_menuItem == NULL -void wxMenuItem::SetName( const wxString& str ) +void wxMenuItem::DoSetText( const wxString& str ) { /* '\t' is the deliminator indicating a hot key */ - m_text = wxT(""); + m_text.Empty(); const wxChar *pc = str; for (; (*pc != wxT('\0')) && (*pc != wxT('\t')); pc++ ) { @@ -639,9 +666,10 @@ void wxMenuItem::Check( bool check ) wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") ) - if (check == m_isChecked) return; + if (check == m_isChecked) + return; - m_isChecked = check; + wxMenuItemBase::Check( check ); gtk_check_menu_item_set_state( (GtkCheckMenuItem*)m_menuItem, (gint)check ); } @@ -650,18 +678,17 @@ void wxMenuItem::Enable( bool enable ) wxCHECK_RET( m_menuItem, wxT("invalid menu item") ); gtk_widget_set_sensitive( m_menuItem, enable ); - m_isEnabled = enable; + wxMenuItemBase::Enable( enable ); } bool wxMenuItem::IsChecked() const { wxCHECK_MSG( m_menuItem, FALSE, wxT("invalid menu item") ); - wxCHECK( IsCheckable(), FALSE ); // can't get state of uncheckable item! - - bool bIsChecked = ((GtkCheckMenuItem*)m_menuItem)->active != 0; + wxCHECK_MSG( IsCheckable(), FALSE, + wxT("can't get state of uncheckable item!") ); - return bIsChecked; + return ((GtkCheckMenuItem*)m_menuItem)->active != 0; } //----------------------------------------------------------------------------- @@ -727,14 +754,14 @@ wxMenu::~wxMenu() while (node) { wxMenuItem *item = (wxMenuItem*)node->Data(); - wxMenu *submenu = item->GetSubMenu(); - if (submenu) - delete submenu; + wxMenu *submenu = item->GetSubMenu(); + if (submenu) + delete submenu; node = node->Next(); } gtk_widget_destroy( m_menu ); - + gtk_object_unref( GTK_OBJECT(m_factory) ); } @@ -751,8 +778,7 @@ const wxString wxMenu::GetTitle() const void wxMenu::AppendSeparator() { - wxMenuItem *mitem = new wxMenuItem(); - mitem->SetId(ID_SEPARATOR); + wxMenuItem *mitem = new wxMenuItem(this, wxID_SEPARATOR); #if (GTK_MINOR_VERSION > 0) GtkItemFactoryEntry entry; @@ -776,53 +802,65 @@ void wxMenu::AppendSeparator() m_items.Append( mitem ); } -#if (GTK_MINOR_VERSION > 0) -static char* GetHotKey( const wxString &hotkey, char *hotbuf ) +#if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL +static wxString GetHotKey( const wxMenuItem& item ) { - if (hotkey.IsEmpty()) return (char*) NULL; + wxString hotkey; - switch (hotkey[0]) + // as wxGetAccelFromString() looks for TAB, insert a dummy one here + wxString label; + label << wxT('\t') << item.GetHotKey(); + wxAcceleratorEntry *accel = wxGetAccelFromString(label); + if ( accel ) { - case wxT('a'): /* Alt */ - case wxT('A'): - case wxT('m'): /* Meta */ - case wxT('M'): - { - strcpy( hotbuf, "" ); - wxString last = hotkey.Right(1); - strcat( hotbuf, last.mb_str() ); - return hotbuf; - } - case wxT('c'): /* Ctrl */ - case wxT('C'): - case wxT('s'): /* Strg, yeah man, I'm German */ - case wxT('S'): - { - strcpy( hotbuf, "" ); - wxString last = hotkey.Right(1); - strcat( hotbuf, last.mb_str() ); - return hotbuf; - } - case wxT('F'): /* function keys */ - { - strcpy( hotbuf, hotkey.mb_str() ); - return hotbuf; - } - default: + int flags = accel->GetFlags(); + if ( flags & wxACCEL_ALT ) + hotkey += wxT(""); + if ( flags & wxACCEL_CTRL ) + hotkey += wxT(""); + if ( flags & wxACCEL_SHIFT ) + hotkey += wxT(""); + + int code = accel->GetKeyCode(); + switch ( code ) { + case WXK_F1: + case WXK_F2: + case WXK_F3: + case WXK_F4: + case WXK_F5: + case WXK_F6: + case WXK_F7: + case WXK_F8: + case WXK_F9: + case WXK_F10: + case WXK_F11: + case WXK_F12: + hotkey << wxT('F') << code = WXK_F1 + 1; + break; + + // if there are any other keys wxGetAccelFromString() may return, + // we should process them here + + default: + if ( wxIsalnum(code) ) + { + hotkey << (wxChar)code; + + break; + } + + wxFAIL_MSG( wxT("unknown keyboard accel") ); } } - return (char*) NULL; + + return hotkey; } -#endif +#endif // wxUSE_ACCEL void wxMenu::Append( int id, const wxString &item, const wxString &helpStr, bool checkable ) { - wxMenuItem *mitem = new wxMenuItem(); - mitem->SetId(id); - mitem->SetText(item); - mitem->SetHelp(helpStr); - mitem->SetCheckable(checkable); + wxMenuItem *mitem = new wxMenuItem(this, id, item, helpStr, checkable); #if (GTK_MINOR_VERSION > 0) /* text has "_" instead of "&" after mitem->SetText() */ @@ -842,8 +880,16 @@ void wxMenu::Append( int id, const wxString &item, const wxString &helpStr, bool else entry.item_type = ""; - char hotbuf[50]; - entry.accelerator = GetHotKey( mitem->GetHotKey(), hotbuf ); +#if wxUSE_ACCEL + // due to an apparent bug in GTK+, we have to use a static buffer here - + // otherwise GTK+ 1.2.2 manages to override the memory we pass to it + // somehow! (VZ) + static char s_accel[32]; // must be big enough for F12 + strncpy(s_accel, GetHotKey(*mitem).mb_str(), WXSIZEOF(s_accel)); + entry.accelerator = s_accel; +#else + entry.accelerator = NULL; +#endif gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ @@ -886,10 +932,7 @@ void wxMenu::Append( int id, const wxString &item, const wxString &helpStr, bool void wxMenu::Append( int id, const wxString &item, wxMenu *subMenu, const wxString &helpStr ) { - wxMenuItem *mitem = new wxMenuItem(); - mitem->SetId(id); - mitem->SetText(item); - mitem->SetHelp(helpStr); + wxMenuItem *mitem = new wxMenuItem(this, id, item, helpStr, FALSE, subMenu); #if (GTK_MINOR_VERSION > 0) /* text has "_" instead of "&" after mitem->SetText() */ @@ -938,7 +981,6 @@ void wxMenu::Append( int id, const wxString &item, wxMenu *subMenu, const wxStri gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), subMenu->m_menu ); mitem->SetMenuItem(menuItem); - mitem->SetSubMenu(subMenu); m_items.Append( mitem ); } @@ -988,8 +1030,8 @@ void wxMenu::Delete( int id ) wxMenuItem *item = (wxMenuItem*)node->Data(); if (item->GetId() == id) { - gtk_widget_destroy( item->GetMenuItem() ); - m_items.DeleteNode( node ); + gtk_widget_destroy( item->GetMenuItem() ); + m_items.DeleteNode( node ); return; } node = node->Next(); diff --git a/src/gtk1/dnd.cpp b/src/gtk1/dnd.cpp index fbd0ec5b86..fdd1f25e8f 100644 --- a/src/gtk1/dnd.cpp +++ b/src/gtk1/dnd.cpp @@ -628,7 +628,7 @@ gtk_dnd_window_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigur if (source->m_dragContext->action == GDK_ACTION_COPY) action = wxDragCopy; if (source->m_dragContext->action == GDK_ACTION_MOVE) action = wxDragMove; - source->GiveFeedback( action, FALSE ); + source->GiveFeedback( action ); return 0; } diff --git a/src/gtk1/menu.cpp b/src/gtk1/menu.cpp index 35a6a05cd0..de0b18636f 100644 --- a/src/gtk1/menu.cpp +++ b/src/gtk1/menu.cpp @@ -17,6 +17,10 @@ #include "wx/intl.h" #include "wx/app.h" +#if wxUSE_ACCEL + #include "wx/accel.h" +#endif // wxUSE_ACCEL + #include "gdk/gdk.h" #include "gtk/gtk.h" @@ -85,7 +89,7 @@ wxMenuBar::wxMenuBar() wxFAIL_MSG( wxT("wxMenuBar creation failed") ); return; } - + m_menus.DeleteContents( TRUE ); /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */ @@ -113,7 +117,7 @@ static void wxMenubarUnsetInvokingWindow( wxMenu *menu, wxWindow *win ) #if (GTK_MINOR_VERSION > 0) wxWindow *top_frame = win; - while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) + while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) top_frame = top_frame->GetParent(); /* support for native hot keys */ @@ -136,7 +140,7 @@ static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win ) #if (GTK_MINOR_VERSION > 0) wxWindow *top_frame = win; - while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) + while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) top_frame = top_frame->GetParent(); /* support for native hot keys */ @@ -158,7 +162,7 @@ void wxMenuBar::SetInvokingWindow( wxWindow *win ) m_invokingWindow = win; #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) wxWindow *top_frame = win; - while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) + while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) top_frame = top_frame->GetParent(); /* support for native key accelerators indicated by underscroes */ @@ -179,7 +183,7 @@ void wxMenuBar::UnsetInvokingWindow( wxWindow *win ) m_invokingWindow = (wxWindow*) NULL; #if (GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 0) wxWindow *top_frame = win; - while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) + while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame)) top_frame = top_frame->GetParent(); /* support for native key accelerators indicated by underscroes */ @@ -257,7 +261,7 @@ void wxMenuBar::Append( wxMenu *menu, const wxString &title ) { // contrary to the common sense, we must throw out _all_ underscores, // (i.e. "Hello__World" => "HelloWorld" and not "Hello_World" as we - // might naively think). IMHO it's a bug in GTK+ (VZ) + // might naively think). IMHO it's a bug in GTK+ (VZ) while (*pc == wxT('_')) pc++; tmp << *pc; @@ -488,15 +492,17 @@ static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu ) if (item->IsCheckable()) { - if (item->GetCheckedFlag() == item->IsChecked()) + bool isReallyChecked = item->IsChecked(); + if ( item->wxMenuItemBase::IsChecked() == isReallyChecked ) { /* the menu item has been checked by calling wxMenuItem->Check() */ return; } else { - /* the user pressed on the menu item -> report */ - item->SetCheckedFlag(item->IsChecked()); /* make consistent again */ + /* the user pressed on the menu item -> report and make consistent + * again */ + item->wxMenuItemBase::Check(isReallyChecked); } } @@ -573,16 +579,37 @@ static void gtk_menu_nolight_callback( GtkWidget *widget, wxMenu *menu ) // wxMenuItem //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxMenuItem,wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxMenuItemBase) + +wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu, + int id, + const wxString& name, + const wxString& help, + bool isCheckable, + wxMenu *subMenu) +{ + return new wxMenuItem(parentMenu, id, name, help, isCheckable, subMenu); +} -wxMenuItem::wxMenuItem() +wxMenuItem::wxMenuItem(wxMenu *parentMenu, + int id, + const wxString& text, + const wxString& help, + bool isCheckable, + wxMenu *subMenu) { - m_id = ID_SEPARATOR; - m_isCheckMenu = FALSE; + m_id = id; + m_isCheckable = isCheckable; m_isChecked = FALSE; m_isEnabled = TRUE; - m_subMenu = (wxMenu *) NULL; + m_subMenu = subMenu; + m_parentMenu = parentMenu; + m_help = help; + m_menuItem = (GtkWidget *) NULL; + + // call it after initializing m_menuItem to NULL + DoSetText(text); } wxMenuItem::~wxMenuItem() @@ -591,10 +618,10 @@ wxMenuItem::~wxMenuItem() } // it's valid for this function to be called even if m_menuItem == NULL -void wxMenuItem::SetName( const wxString& str ) +void wxMenuItem::DoSetText( const wxString& str ) { /* '\t' is the deliminator indicating a hot key */ - m_text = wxT(""); + m_text.Empty(); const wxChar *pc = str; for (; (*pc != wxT('\0')) && (*pc != wxT('\t')); pc++ ) { @@ -639,9 +666,10 @@ void wxMenuItem::Check( bool check ) wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") ) - if (check == m_isChecked) return; + if (check == m_isChecked) + return; - m_isChecked = check; + wxMenuItemBase::Check( check ); gtk_check_menu_item_set_state( (GtkCheckMenuItem*)m_menuItem, (gint)check ); } @@ -650,18 +678,17 @@ void wxMenuItem::Enable( bool enable ) wxCHECK_RET( m_menuItem, wxT("invalid menu item") ); gtk_widget_set_sensitive( m_menuItem, enable ); - m_isEnabled = enable; + wxMenuItemBase::Enable( enable ); } bool wxMenuItem::IsChecked() const { wxCHECK_MSG( m_menuItem, FALSE, wxT("invalid menu item") ); - wxCHECK( IsCheckable(), FALSE ); // can't get state of uncheckable item! - - bool bIsChecked = ((GtkCheckMenuItem*)m_menuItem)->active != 0; + wxCHECK_MSG( IsCheckable(), FALSE, + wxT("can't get state of uncheckable item!") ); - return bIsChecked; + return ((GtkCheckMenuItem*)m_menuItem)->active != 0; } //----------------------------------------------------------------------------- @@ -727,14 +754,14 @@ wxMenu::~wxMenu() while (node) { wxMenuItem *item = (wxMenuItem*)node->Data(); - wxMenu *submenu = item->GetSubMenu(); - if (submenu) - delete submenu; + wxMenu *submenu = item->GetSubMenu(); + if (submenu) + delete submenu; node = node->Next(); } gtk_widget_destroy( m_menu ); - + gtk_object_unref( GTK_OBJECT(m_factory) ); } @@ -751,8 +778,7 @@ const wxString wxMenu::GetTitle() const void wxMenu::AppendSeparator() { - wxMenuItem *mitem = new wxMenuItem(); - mitem->SetId(ID_SEPARATOR); + wxMenuItem *mitem = new wxMenuItem(this, wxID_SEPARATOR); #if (GTK_MINOR_VERSION > 0) GtkItemFactoryEntry entry; @@ -776,53 +802,65 @@ void wxMenu::AppendSeparator() m_items.Append( mitem ); } -#if (GTK_MINOR_VERSION > 0) -static char* GetHotKey( const wxString &hotkey, char *hotbuf ) +#if (GTK_MINOR_VERSION > 0) && wxUSE_ACCEL +static wxString GetHotKey( const wxMenuItem& item ) { - if (hotkey.IsEmpty()) return (char*) NULL; + wxString hotkey; - switch (hotkey[0]) + // as wxGetAccelFromString() looks for TAB, insert a dummy one here + wxString label; + label << wxT('\t') << item.GetHotKey(); + wxAcceleratorEntry *accel = wxGetAccelFromString(label); + if ( accel ) { - case wxT('a'): /* Alt */ - case wxT('A'): - case wxT('m'): /* Meta */ - case wxT('M'): - { - strcpy( hotbuf, "" ); - wxString last = hotkey.Right(1); - strcat( hotbuf, last.mb_str() ); - return hotbuf; - } - case wxT('c'): /* Ctrl */ - case wxT('C'): - case wxT('s'): /* Strg, yeah man, I'm German */ - case wxT('S'): - { - strcpy( hotbuf, "" ); - wxString last = hotkey.Right(1); - strcat( hotbuf, last.mb_str() ); - return hotbuf; - } - case wxT('F'): /* function keys */ - { - strcpy( hotbuf, hotkey.mb_str() ); - return hotbuf; - } - default: + int flags = accel->GetFlags(); + if ( flags & wxACCEL_ALT ) + hotkey += wxT(""); + if ( flags & wxACCEL_CTRL ) + hotkey += wxT(""); + if ( flags & wxACCEL_SHIFT ) + hotkey += wxT(""); + + int code = accel->GetKeyCode(); + switch ( code ) { + case WXK_F1: + case WXK_F2: + case WXK_F3: + case WXK_F4: + case WXK_F5: + case WXK_F6: + case WXK_F7: + case WXK_F8: + case WXK_F9: + case WXK_F10: + case WXK_F11: + case WXK_F12: + hotkey << wxT('F') << code = WXK_F1 + 1; + break; + + // if there are any other keys wxGetAccelFromString() may return, + // we should process them here + + default: + if ( wxIsalnum(code) ) + { + hotkey << (wxChar)code; + + break; + } + + wxFAIL_MSG( wxT("unknown keyboard accel") ); } } - return (char*) NULL; + + return hotkey; } -#endif +#endif // wxUSE_ACCEL void wxMenu::Append( int id, const wxString &item, const wxString &helpStr, bool checkable ) { - wxMenuItem *mitem = new wxMenuItem(); - mitem->SetId(id); - mitem->SetText(item); - mitem->SetHelp(helpStr); - mitem->SetCheckable(checkable); + wxMenuItem *mitem = new wxMenuItem(this, id, item, helpStr, checkable); #if (GTK_MINOR_VERSION > 0) /* text has "_" instead of "&" after mitem->SetText() */ @@ -842,8 +880,16 @@ void wxMenu::Append( int id, const wxString &item, const wxString &helpStr, bool else entry.item_type = ""; - char hotbuf[50]; - entry.accelerator = GetHotKey( mitem->GetHotKey(), hotbuf ); +#if wxUSE_ACCEL + // due to an apparent bug in GTK+, we have to use a static buffer here - + // otherwise GTK+ 1.2.2 manages to override the memory we pass to it + // somehow! (VZ) + static char s_accel[32]; // must be big enough for F12 + strncpy(s_accel, GetHotKey(*mitem).mb_str(), WXSIZEOF(s_accel)); + entry.accelerator = s_accel; +#else + entry.accelerator = NULL; +#endif gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 ); /* what is 2 ? */ @@ -886,10 +932,7 @@ void wxMenu::Append( int id, const wxString &item, const wxString &helpStr, bool void wxMenu::Append( int id, const wxString &item, wxMenu *subMenu, const wxString &helpStr ) { - wxMenuItem *mitem = new wxMenuItem(); - mitem->SetId(id); - mitem->SetText(item); - mitem->SetHelp(helpStr); + wxMenuItem *mitem = new wxMenuItem(this, id, item, helpStr, FALSE, subMenu); #if (GTK_MINOR_VERSION > 0) /* text has "_" instead of "&" after mitem->SetText() */ @@ -938,7 +981,6 @@ void wxMenu::Append( int id, const wxString &item, wxMenu *subMenu, const wxStri gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), subMenu->m_menu ); mitem->SetMenuItem(menuItem); - mitem->SetSubMenu(subMenu); m_items.Append( mitem ); } @@ -988,8 +1030,8 @@ void wxMenu::Delete( int id ) wxMenuItem *item = (wxMenuItem*)node->Data(); if (item->GetId() == id) { - gtk_widget_destroy( item->GetMenuItem() ); - m_items.DeleteNode( node ); + gtk_widget_destroy( item->GetMenuItem() ); + m_items.DeleteNode( node ); return; } node = node->Next(); diff --git a/src/msw/menu.cpp b/src/msw/menu.cpp index de144548e1..1d5ff12350 100644 --- a/src/msw/menu.cpp +++ b/src/msw/menu.cpp @@ -141,78 +141,9 @@ void wxMenu::Append(wxMenuItem *pItem) wxCHECK_RET( pItem != NULL, wxT("can't append NULL item to the menu") ); #if wxUSE_ACCEL - // check for accelerators: they are given after '\t' - wxString label = pItem->GetName(); - int posTab = label.Find(wxT('\t')); - if ( posTab != wxNOT_FOUND ) { - // parse the accelerator string - int keyCode = 0; - int accelFlags = wxACCEL_NORMAL; - wxString current; - for ( size_t n = (size_t)posTab + 1; n < label.Len(); n++ ) { - if ( (label[n] == '+') || (label[n] == '-') ) { - if ( current == _("ctrl") ) - accelFlags |= wxACCEL_CTRL; - else if ( current == _("alt") ) - accelFlags |= wxACCEL_ALT; - else if ( current == _("shift") ) - accelFlags |= wxACCEL_SHIFT; - else { - wxLogDebug(wxT("Unknown accel modifier: '%s'"), - current.c_str()); - } - - current.Empty(); - } - else { - current += wxTolower(label[n]); - } - } - - if ( current.IsEmpty() ) { - wxLogDebug(wxT("No accel key found, accel string ignored.")); - } - else { - if ( current.Len() == 1 ) { - // it's a letter - keyCode = wxToupper(current[0U]); - } - else { - // is it a function key? - if ( current[0U] == 'f' && isdigit(current[1U]) && - (current.Len() == 2 || - (current.Len() == 3 && isdigit(current[2U]))) ) { - int n; - wxSscanf(current.c_str() + 1, wxT("%d"), &n); - - keyCode = VK_F1 + n - 1; - } - else { - // several special cases - current.MakeUpper(); - if ( current == wxT("DEL") ) { - keyCode = VK_DELETE; - } - else if ( current == wxT("PGUP") ) { - keyCode = VK_PRIOR; - } - else if ( current == wxT("PGDN") ) { - keyCode = VK_NEXT; - } - else { - wxLogDebug(wxT("Unrecognized accel key '%s', accel " - "string ignored."), current.c_str()); - } - } - } - } - - if ( keyCode ) { - // do add an entry - m_accelKeyCodes.Add(keyCode); - m_accelFlags.Add(accelFlags); - m_accelIds.Add(pItem->GetId()); - } + wxAcceleratorEntry *accel = wxGetAccelFromMenuLabel(pItem->GetText()); + if ( accel ) { + m_accels.Add(accel); } #endif // wxUSE_ACCEL @@ -262,13 +193,7 @@ void wxMenu::Append(wxMenuItem *pItem) // menu is just a normal string (passed in data parameter) flags |= MF_STRING; -// Don't know what the correct cast should be, but it doesn't -// compile in BC++/16-bit without this cast. -#if !defined(__WIN32__) - pData = (char*) (const char*) label; -#else - pData = label; -#endif + pData = (char*)pItem->GetText().c_str(); } if ( !::AppendMenu(GetHmenu(), flags, id, pData) ) @@ -373,7 +298,7 @@ size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const size_t count = GetAccelCount(); for ( size_t n = 0; n < count; n++ ) { - (*accels++).Set(m_accelFlags[n], m_accelKeyCodes[n], m_accelIds[n]); + *accels++ = *m_accels[n]; } return count; @@ -422,7 +347,7 @@ void wxMenu::SetLabel(int id, const wxString& label) wxMenuItem *item = FindItemForId(id) ; wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") ); - item->SetName(label); + item->SetText(label); } wxString wxMenu::GetLabel(int id) const @@ -430,7 +355,7 @@ wxString wxMenu::GetLabel(int id) const wxString label; wxMenuItem *pItem = FindItemForId(id) ; if (pItem) - label = pItem->GetName() ; + label = pItem->GetText() ; else wxFAIL_MSG(wxT("wxMenu::GetLabel: item doesn't exist")); @@ -592,7 +517,7 @@ int wxMenu::FindItem (const wxString& itemString) const } else if ( !item->IsSeparator() ) { - wxString label = wxStripMenuCodes(item->GetName()); + wxString label = wxStripMenuCodes(item->GetText()); if ( itemLabel == label ) return item->GetId(); } @@ -812,7 +737,7 @@ void wxMenuBar::SetLabel(int id, const wxString& label) wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") ); - item->SetName(label); + item->SetText(label); } wxString wxMenuBar::GetLabel(int id) const @@ -820,9 +745,10 @@ wxString wxMenuBar::GetLabel(int id) const wxMenu *itemMenu = NULL; wxMenuItem *item = FindItemForId(id, &itemMenu) ; - wxCHECK_MSG( item, wxT(""), wxT("wxMenuBar::GetLabel(): no such item") ); + wxCHECK_MSG( item, wxEmptyString, + wxT("wxMenuBar::GetLabel(): no such item") ); - return item->GetName(); + return item->GetText(); } void wxMenuBar::SetHelpString (int id, const wxString& helpString) diff --git a/src/msw/menuitem.cpp b/src/msw/menuitem.cpp index a4f038f875..09c4986f15 100644 --- a/src/msw/menuitem.cpp +++ b/src/msw/menuitem.cpp @@ -39,18 +39,25 @@ #include "wx/string.h" #endif -#include "wx/ownerdrw.h" #include "wx/menuitem.h" #include "wx/log.h" #include "wx/msw/private.h" // --------------------------------------------------------------------------- -// convenience macro +// macro // --------------------------------------------------------------------------- +// hide the ugly cast #define GetHMenuOf(menu) ((HMENU)menu->GetHMenu()) +// conditional compilation +#if wxUSE_OWNER_DRAWN + #define OWNER_DRAWN_ONLY( code ) if ( IsOwnerDrawn() ) code +#else // !wxUSE_OWNER_DRAWN + #define OWNER_DRAWN_ONLY( code ) +#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN + // ============================================================================ // implementation // ============================================================================ @@ -60,12 +67,11 @@ // ---------------------------------------------------------------------------- #if !defined(USE_SHARED_LIBRARY) || !USE_SHARED_LIBRARY -#if wxUSE_OWNER_DRAWN - IMPLEMENT_DYNAMIC_CLASS2(wxMenuItem, wxObject, wxOwnerDrawn) -#else //!USE_OWNER_DRAWN - IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject) -#endif //USE_OWNER_DRAWN - + #if wxUSE_OWNER_DRAWN + IMPLEMENT_DYNAMIC_CLASS2(wxMenuItem, wxMenuItemBase, wxOwnerDrawn) + #else //!USE_OWNER_DRAWN + IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxMenuItemBase) + #endif //USE_OWNER_DRAWN #endif //USE_SHARED_LIBRARY // ---------------------------------------------------------------------------- @@ -75,17 +81,15 @@ // ctor & dtor // ----------- -wxMenuItem::wxMenuItem(wxMenu *pParentMenu, int id, - const wxString& strName, const wxString& strHelp, +wxMenuItem::wxMenuItem(wxMenu *pParentMenu, + int id, + const wxString& text, + const wxString& strHelp, bool bCheckable, wxMenu *pSubMenu) : #if wxUSE_OWNER_DRAWN - wxOwnerDrawn(strName, bCheckable), -#else //no owner drawn support - m_bCheckable(bCheckable), - m_strName(strName), -#endif //owner drawn - m_strHelp(strHelp) + wxOwnerDrawn(text, bCheckable) +#endif // owner drawn { wxASSERT_MSG( pParentMenu != NULL, wxT("a menu item should have a parent") ); @@ -100,13 +104,16 @@ wxMenuItem::wxMenuItem(wxMenu *pParentMenu, int id, ResetOwnerDrawn(); #undef SYS_COLOR -#endif - - m_pParentMenu = pParentMenu; - m_pSubMenu = pSubMenu; - m_bEnabled = TRUE; - m_bChecked = FALSE; - m_idItem = id; +#endif // wxUSE_OWNER_DRAWN + + m_parentMenu = pParentMenu; + m_subMenu = pSubMenu; + m_isEnabled = TRUE; + m_isChecked = FALSE; + m_id = id; + m_text = text; + m_isCheckable = bCheckable; + m_help = strHelp; } wxMenuItem::~wxMenuItem() @@ -119,15 +126,15 @@ wxMenuItem::~wxMenuItem() // return the id for calling Win32 API functions int wxMenuItem::GetRealId() const { - return m_pSubMenu ? (int)m_pSubMenu->GetHMenu() : GetId(); + return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId(); } // delete the sub menu // ------------------- void wxMenuItem::DeleteSubMenu() { - delete m_pSubMenu; - m_pSubMenu = NULL; + delete m_subMenu; + m_subMenu = NULL; } // change item state @@ -135,8 +142,8 @@ void wxMenuItem::DeleteSubMenu() void wxMenuItem::Enable(bool bDoEnable) { - if ( m_bEnabled != bDoEnable ) { - long rc = EnableMenuItem(GetHMenuOf(m_pParentMenu), + if ( m_isEnabled != bDoEnable ) { + long rc = EnableMenuItem(GetHMenuOf(m_parentMenu), GetRealId(), MF_BYCOMMAND | (bDoEnable ? MF_ENABLED : MF_GRAYED)); @@ -145,16 +152,16 @@ void wxMenuItem::Enable(bool bDoEnable) wxLogLastError("EnableMenuItem"); } - m_bEnabled = bDoEnable; + wxMenuItemBase::Enable(m_isEnabled); } } void wxMenuItem::Check(bool bDoCheck) { - wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") ); + wxCHECK_RET( m_isCheckable, wxT("only checkable items may be checked") ); - if ( m_bChecked != bDoCheck ) { - long rc = CheckMenuItem(GetHMenuOf(m_pParentMenu), + if ( m_isChecked != bDoCheck ) { + long rc = CheckMenuItem(GetHMenuOf(m_parentMenu), GetId(), MF_BYCOMMAND | (bDoCheck ? MF_CHECKED : MF_UNCHECKED)); @@ -163,19 +170,20 @@ void wxMenuItem::Check(bool bDoCheck) wxLogLastError("CheckMenuItem"); } - m_bChecked = bDoCheck; + wxMenuItemBase::Check(m_isChecked); } } -void wxMenuItem::SetName(const wxString& strName) +void wxMenuItem::SetText(const wxString& text) { // don't do anything if label didn't change - if ( m_strName == strName ) + if ( m_text == text ) return; - m_strName = strName; + wxMenuItemBase::SetText(text); + OWNER_DRAWN_ONLY( wxOwnerDrawn::SetName(text) ); - HMENU hMenu = GetHMenuOf(m_pParentMenu); + HMENU hMenu = GetHMenuOf(m_parentMenu); UINT id = GetRealId(); UINT flagsOld = ::GetMenuState(hMenu, id, MF_BYCOMMAND); @@ -193,6 +201,7 @@ void wxMenuItem::SetName(const wxString& strName) } LPCTSTR data; + #if wxUSE_OWNER_DRAWN if ( IsOwnerDrawn() ) { @@ -203,13 +212,7 @@ void wxMenuItem::SetName(const wxString& strName) #endif //owner drawn { flagsOld |= MF_STRING; -// Don't know what the correct cast should be, but it doesn't -// compile in BC++/16-bit without this cast. -#if !defined(__WIN32__) - data = (char*) (const char*) strName; -#else - data = strName; -#endif + data = (char*) text.c_str(); } if ( ::ModifyMenu(hMenu, id, @@ -221,3 +224,22 @@ void wxMenuItem::SetName(const wxString& strName) } } +void wxMenuItem::SetCheckable(bool checkable) +{ + wxMenuItemBase::SetCheckable(checkable); + OWNER_DRAWN_ONLY( wxOwnerDrawn::SetCheckable(checkable) ); +} + +// ---------------------------------------------------------------------------- +// wxMenuItemBase +// ---------------------------------------------------------------------------- + +wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu, + int id, + const wxString& name, + const wxString& help, + bool isCheckable, + wxMenu *subMenu) +{ + return new wxMenuItem(parentMenu, id, name, help, isCheckable, subMenu); +} -- 2.47.2