From c2dcfdef634e097f7efe2288aa13511efb43ae28 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 3 Apr 1999 22:25:12 +0000 Subject: [PATCH] wxMenu and wxMenuBar modifications: now works much better with owner-drawn items, better encapsulation (the wxMenu data members are no longer public), simplified wxFrame and derived classes by moving the common parts into member functions of wxMenuBar git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@2039 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/menu.h | 52 ++- include/wx/msw/menuitem.h | 11 +- include/wx/ownerdrw.h | 55 ++-- src/msw/frame.cpp | 63 ++-- src/msw/mdi.cpp | 236 ++++++------- src/msw/menu.cpp | 673 ++++++++++++++++++++------------------ src/msw/menuitem.cpp | 163 ++++++--- 7 files changed, 666 insertions(+), 587 deletions(-) diff --git a/include/wx/msw/menu.h b/include/wx/msw/menu.h index 65479f5b20..583ec5432c 100644 --- a/include/wx/msw/menu.h +++ b/include/wx/msw/menu.h @@ -129,10 +129,13 @@ public: // get the menu handle WXHMENU GetHMenu() const; -private: - bool m_doBreak ; + // only for wxMenuBar + void Attach(wxMenuBar *menubar); + void Detach(); + +private: + bool m_doBreak; -public: // This is used when m_hMenu is NULL because we don't want to // delete it in ~wxMenu (it's been added to a parent menu). // But we'll still need the handle for other purposes. @@ -162,12 +165,16 @@ class WXDLLEXPORT wxMenuBar : public wxEvtHandler public: // ctors & dtor + // default constructor wxMenuBar(); + // unused under MSW wxMenuBar(long style); + // menubar takes ownership of the menus arrays but copies the titles wxMenuBar(int n, wxMenu *menus[], const wxString titles[]); virtual ~wxMenuBar(); // menubar construction + WXHMENU Create(); void Append(wxMenu *menu, const wxString& title); virtual void Delete(wxMenu *menu, int index = 0); /* Menu not destroyed */ @@ -195,7 +202,8 @@ public: void SetLabelTop(int pos, const wxString& label) ; wxString GetLabelTop(int pos) const ; - // notifications + // notifications: return FALSE to prevent the menu from being + // appended/deleted virtual bool OnAppend(wxMenu *menu, const char *title); virtual bool OnDelete(wxMenu *menu, int index); @@ -221,13 +229,35 @@ public: bool Checked(int id) const { return IsChecked(id); } #endif // WXWIN_COMPATIBILITY -public: - wxEvtHandler * m_eventHandler; - int m_menuCount; - wxMenu ** m_menus; - wxString * m_titles; - wxFrame * m_menuBarFrame; - WXHMENU m_hMenu; + // IMPLEMENTATION + // returns TRUE if we're attached to a frame + bool IsAttached() const { return m_menuBarFrame != NULL; } + // get the frame we live in + wxFrame *GetFrame() const { return m_menuBarFrame; } + // attach to a frame + void Attach(wxFrame *frame) + { + wxASSERT_MSG( !m_menuBarFrame, "menubar already attached!" ); + + m_menuBarFrame = frame; + } + // get the menu handle + WXHMENU GetHMenu() const { return m_hMenu; } + +protected: + // common part of all ctors + void Init(); + + // if the menubar is modified, the display is not updated automatically, + // call this function to update it (m_menuBarFrame should be !NULL) + void Refresh(); + + wxEvtHandler *m_eventHandler; + int m_menuCount; + wxMenu **m_menus; + wxString *m_titles; + wxFrame *m_menuBarFrame; + WXHMENU m_hMenu; }; #endif // _WX_MENU_H_ diff --git a/include/wx/msw/menuitem.h b/include/wx/msw/menuitem.h index cbe61b535f..28e8e1c9db 100644 --- a/include/wx/msw/menuitem.h +++ b/include/wx/msw/menuitem.h @@ -55,15 +55,20 @@ public: // 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 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) { m_strName = strName; } + void SetName(const wxString& strName); void SetHelp(const wxString& strHelp) { m_strHelp = strHelp; } void Enable(bool bDoEnable = TRUE); diff --git a/include/wx/ownerdrw.h b/include/wx/ownerdrw.h index 5a742f3dda..fa89707d20 100644 --- a/include/wx/ownerdrw.h +++ b/include/wx/ownerdrw.h @@ -16,8 +16,6 @@ #pragma interface "ownerdrw.h" #endif -// No, don't do this: BC++ 5 complains that size_t already been defined. -// typedef unsigned int size_t; #include // ---------------------------------------------------------------------------- @@ -34,34 +32,34 @@ public: // ctor & dtor wxOwnerDrawn(const wxString& str = "", bool bCheckable = FALSE, - bool bMenuItem = FALSE); // @@ kludge for colors + bool bMenuItem = FALSE); // FIXME kludge for colors virtual ~wxOwnerDrawn() { } // fix appearance - inline void SetFont(const wxFont& font) - { m_font = font; m_bOwnerDrawn = TRUE; } + void SetFont(const wxFont& font) + { m_font = font; m_bOwnerDrawn = TRUE; } - inline wxFont& GetFont() const { return (wxFont &)m_font; } + wxFont& GetFont() const { return (wxFont &)m_font; } - inline void SetTextColour(const wxColour& colText) - { m_colText = colText; m_bOwnerDrawn = TRUE; } + void SetTextColour(const wxColour& colText) + { m_colText = colText; m_bOwnerDrawn = TRUE; } - inline wxColour& GetTextColour() const { return (wxColour&) m_colText; } + wxColour& GetTextColour() const { return (wxColour&) m_colText; } - inline void SetBackgroundColour(const wxColour& colBack) - { m_colBack = colBack; m_bOwnerDrawn = TRUE; } + void SetBackgroundColour(const wxColour& colBack) + { m_colBack = colBack; m_bOwnerDrawn = TRUE; } - inline wxColour& GetBackgroundColour() const - { return (wxColour&) m_colBack ; } + wxColour& GetBackgroundColour() const + { return (wxColour&) m_colBack ; } - inline void SetBitmaps(const wxBitmap& bmpChecked, - const wxBitmap& bmpUnchecked = wxNullBitmap) - { m_bmpChecked = bmpChecked; - m_bmpUnchecked = bmpUnchecked; - m_bOwnerDrawn = TRUE; } + void SetBitmaps(const wxBitmap& bmpChecked, + const wxBitmap& bmpUnchecked = wxNullBitmap) + { m_bmpChecked = bmpChecked; + m_bmpUnchecked = bmpUnchecked; + m_bOwnerDrawn = TRUE; } - inline const wxBitmap& GetBitmap(bool bChecked = TRUE) const - { return (bChecked ? m_bmpChecked : m_bmpUnchecked); } + const wxBitmap& GetBitmap(bool bChecked = TRUE) const + { return (bChecked ? m_bmpChecked : m_bmpUnchecked); } // the height of the menu checkmark (or bitmap) is determined by the font // for the current item, but the width should be always the same (for the @@ -69,12 +67,15 @@ public: // the last item (and default width for the first one). // // NB: default is too small for bitmaps, but ok for checkmarks. - inline void SetMarginWidth(int nWidth) - { ms_nLastMarginWidth = m_nMarginWidth = (size_t) nWidth; - if ( ((size_t) nWidth) != ms_nDefaultMarginWidth ) m_bOwnerDrawn = TRUE; } + void SetMarginWidth(int nWidth) + { + ms_nLastMarginWidth = m_nMarginWidth = (size_t) nWidth; + if ( ((size_t) nWidth) != ms_nDefaultMarginWidth ) + m_bOwnerDrawn = TRUE; + } - inline int GetMarginWidth() const { return (int) m_nMarginWidth; } - inline static int GetDefaultMarginWidth() { return (int) ms_nDefaultMarginWidth; } + int GetMarginWidth() const { return (int) m_nMarginWidth; } + static int GetDefaultMarginWidth() { return (int) ms_nDefaultMarginWidth; } // accessors void SetName(const wxString& strName) { m_strName = strName; } @@ -86,8 +87,8 @@ public: // 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) - inline bool IsOwnerDrawn() const { return m_bOwnerDrawn; } - inline void ResetOwnerDrawn() { m_bOwnerDrawn = FALSE; } + bool IsOwnerDrawn() const { return m_bOwnerDrawn; } + void ResetOwnerDrawn() { m_bOwnerDrawn = FALSE; } public: // constants used in OnDrawItem diff --git a/src/msw/frame.cpp b/src/msw/frame.cpp index 03a362b615..811bea77ca 100644 --- a/src/msw/frame.cpp +++ b/src/msw/frame.cpp @@ -398,7 +398,7 @@ wxStatusBar* wxFrame::CreateStatusBar(int number, long style, wxWindowID id, const wxString& name) { // VZ: calling CreateStatusBar twice is an error - why anyone would do it? - wxCHECK_MSG( m_frameStatusBar == NULL, FALSE, + wxCHECK_MSG( m_frameStatusBar == NULL, FALSE, "recreating status bar in wxFrame" ); m_frameStatusBar = OnCreateStatusBar(number, style, id, @@ -449,48 +449,29 @@ void wxFrame::PositionStatusBar() void wxFrame::SetMenuBar(wxMenuBar *menu_bar) { - if (!menu_bar) - { - m_frameMenuBar = NULL; - return; - } - - if (menu_bar->m_menuBarFrame) - return; + if (!menu_bar) + { + m_frameMenuBar = NULL; + return; + } - int i; - HMENU menu = CreateMenu(); + wxCHECK_RET( !menu_bar->GetFrame(), "this menubar is already attached" ); - for (i = 0; i < menu_bar->m_menuCount; i ++) - { - HMENU popup = (HMENU)menu_bar->m_menus[i]->m_hMenu; - // - // After looking Bounds Checker result, it seems that all - // menus must be individually destroyed. So, don't reset m_hMenu, - // to allow ~wxMenu to do the job. - // - menu_bar->m_menus[i]->m_savehMenu = (WXHMENU) popup; - // Uncommenting for the moment... JACS - menu_bar->m_menus[i]->m_hMenu = 0; - AppendMenu(menu, MF_POPUP | MF_STRING, (UINT)popup, menu_bar->m_titles[i]); - } + if (m_frameMenuBar) + delete m_frameMenuBar; - menu_bar->m_hMenu = (WXHMENU)menu; - if (m_frameMenuBar) - delete m_frameMenuBar; + m_hMenu = menu_bar->Create(); - this->m_hMenu = (WXHMENU) menu; + if ( !m_hMenu ) + return; - DWORD err = 0; - if (!SetMenu((HWND) GetHWND(), menu)) - { -#ifdef __WIN32__ - err = GetLastError(); -#endif - } + if ( !::SetMenu((HWND)GetHWND(), (HMENU)m_hMenu) ) + { + wxLogLastError("SetMenu"); + } - m_frameMenuBar = menu_bar; - menu_bar->m_menuBarFrame = this; + m_frameMenuBar = menu_bar; + menu_bar->Attach(this); } #if 0 @@ -650,10 +631,10 @@ bool wxFrame::MSWOnPaint() // Hold a pointer to the dc so long as the OnPaint() message // is being processed HDC cdc = BeginPaint((HWND) GetHWND(), &ps); - + // Erase background before painting or we get white background this->MSWDefWindowProc(WM_ICONERASEBKGND,(WORD)(LONG) ps.hdc,0L); - + if (the_icon) { RECT rect; @@ -798,7 +779,7 @@ bool wxFrame::MSWTranslateMessage(WXMSG* pMsg) if (m_acceleratorTable.Ok() && ::TranslateAccelerator((HWND) GetHWND(), (HACCEL) m_acceleratorTable.GetHACCEL(), (MSG *)pMsg)) return TRUE; - + return FALSE; } @@ -820,7 +801,7 @@ void wxFrame::OnSize(wxSizeEvent& event) { wxWindow *win = (wxWindow *)node->Data(); if ( !win->IsKindOf(CLASSINFO(wxFrame)) && - !win->IsKindOf(CLASSINFO(wxDialog)) && + !win->IsKindOf(CLASSINFO(wxDialog)) && (win != GetStatusBar()) && (win != GetToolBar()) ) { diff --git a/src/msw/mdi.cpp b/src/msw/mdi.cpp index d22ac24e76..2b1b74d1b7 100644 --- a/src/msw/mdi.cpp +++ b/src/msw/mdi.cpp @@ -6,7 +6,7 @@ // Created: 04/01/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ @@ -77,7 +77,7 @@ END_EVENT_TABLE() #endif -wxMDIParentFrame::wxMDIParentFrame(void) +wxMDIParentFrame::wxMDIParentFrame() { m_clientWindow = NULL; m_currentChild = NULL; @@ -149,7 +149,7 @@ bool wxMDIParentFrame::Create(wxWindow *parent, return TRUE; } -wxMDIParentFrame::~wxMDIParentFrame(void) +wxMDIParentFrame::~wxMDIParentFrame() { DestroyChildren(); @@ -157,7 +157,7 @@ wxMDIParentFrame::~wxMDIParentFrame(void) m_windowMenu = 0; if (m_clientWindow->MSWGetOldWndProc()) - m_clientWindow->UnsubclassWin(); + m_clientWindow->UnsubclassWin(); m_clientWindow->m_hWnd = 0; delete m_clientWindow; @@ -174,9 +174,9 @@ void wxMDIParentFrame::GetClientSize(int *x, int *y) const if ( GetStatusBar() ) { - int sw, sh; - GetStatusBar()->GetSize(&sw, &sh); - cheight -= sh; + int sw, sh; + GetStatusBar()->GetSize(&sw, &sh); + cheight -= sh; } wxPoint pt(GetClientAreaOrigin()); @@ -194,41 +194,24 @@ void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar) m_frameMenuBar = NULL; return; } - - if (menu_bar->m_menuBarFrame) - return; - int i; - HMENU menu = CreateMenu(); + if ( menu_bar->IsAttached() ) + return; - for (i = 0; i < menu_bar->m_menuCount; i ++) - { - HMENU popup = (HMENU)menu_bar->m_menus[i]->m_hMenu; - // - // After looking Bounds Checker result, it seems that all - // menus must be individually destroyed. So, don't reset m_hMenu, - // to allow ~wxMenu to do the job. - // - menu_bar->m_menus[i]->m_savehMenu = (WXHMENU) popup; - // Uncommenting for the moment... JACS - menu_bar->m_menus[i]->m_hMenu = (WXHMENU) NULL; - AppendMenu(menu, MF_POPUP | MF_STRING, (UINT)popup, menu_bar->m_titles[i]); - } + m_hMenu = menu_bar->Create(); - menu_bar->m_hMenu = (WXHMENU)menu; if (m_frameMenuBar) delete m_frameMenuBar; - this->m_hMenu = (WXHMENU) menu; - // MDI parent-specific code follows HMENU subMenu = GetSubMenu((HMENU) m_windowMenu, 0); // Try to insert Window menu in front of Help, otherwise append it. + HMENU menu = (HMENU)m_hMenu; int N = GetMenuItemCount(menu); bool success = FALSE; - for (i = 0; i < N; i++) + for (int i = 0; i < N; i++) { char buf[100]; int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION); @@ -257,7 +240,7 @@ void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar) DrawMenuBar((HWND) GetHWND()); m_frameMenuBar = menu_bar; - menu_bar->m_menuBarFrame = this; + menu_bar->Attach(this); } void wxMDIParentFrame::OnSize(wxSizeEvent& event) @@ -286,11 +269,11 @@ void wxMDIParentFrame::OnSize(wxSizeEvent& event) void wxMDIParentFrame::OnActivate(wxActivateEvent& event) { - // Do nothing + // Do nothing } // Returns the active MDI child window -wxMDIChildFrame *wxMDIParentFrame::GetActiveChild(void) const +wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const { // HWND hWnd = (HWND)LOWORD(SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIGETACTIVE, 0, 0L)); HWND hWnd = (HWND)SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIGETACTIVE, 0, 0L); @@ -302,9 +285,9 @@ wxMDIChildFrame *wxMDIParentFrame::GetActiveChild(void) const // Create the client window class (don't Create the window, // just return a new class) -wxMDIClientWindow *wxMDIParentFrame::OnCreateClient(void) +wxMDIClientWindow *wxMDIParentFrame::OnCreateClient() { - return new wxMDIClientWindow ; + return new wxMDIClientWindow ; } // Responds to colour changes, and passes event on to children. @@ -329,27 +312,27 @@ void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event) } // MDI operations -void wxMDIParentFrame::Cascade(void) +void wxMDIParentFrame::Cascade() { ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDICASCADE, 0, 0); } -void wxMDIParentFrame::Tile(void) +void wxMDIParentFrame::Tile() { ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDITILE, MDITILE_HORIZONTAL, 0); } -void wxMDIParentFrame::ArrangeIcons(void) +void wxMDIParentFrame::ArrangeIcons() { ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIICONARRANGE, 0, 0); } -void wxMDIParentFrame::ActivateNext(void) +void wxMDIParentFrame::ActivateNext() { ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 0); } -void wxMDIParentFrame::ActivatePrevious(void) +void wxMDIParentFrame::ActivatePrevious() { ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 1); } @@ -358,22 +341,22 @@ void wxMDIParentFrame::ActivatePrevious(void) /* // Returns a style for the client window - usually 0 // or, for example, wxHSCROLL | wxVSCROLL -long wxMDIParentFrame::GetClientStyle(void) const +long wxMDIParentFrame::GetClientStyle() const { - return wxHSCROLL | wxVSCROLL ; + return wxHSCROLL | wxVSCROLL ; } */ -bool wxMDIParentFrame::MSWOnDestroy(void) +bool wxMDIParentFrame::MSWOnDestroy() { return FALSE; } void wxMDIParentFrame::MSWOnCreate(WXLPCREATESTRUCT WXUNUSED(cs)) { - m_clientWindow = OnCreateClient(); - // Uses own style for client style - m_clientWindow->CreateClient(this, GetWindowStyleFlag()); + m_clientWindow = OnCreateClient(); + // Uses own style for client style + m_clientWindow->CreateClient(this, GetWindowStyleFlag()); } void wxMDIParentFrame::MSWOnSize(int x, int y, WXUINT id) @@ -402,7 +385,7 @@ void wxMDIParentFrame::MSWOnSize(int x, int y, WXUINT id) } #endif - PositionStatusBar(); + PositionStatusBar(); PositionToolBar(); wxSizeEvent event(wxSize(x, y), m_windowId); @@ -414,12 +397,12 @@ void wxMDIParentFrame::MSWOnSize(int x, int y, WXUINT id) bool wxMDIParentFrame::MSWOnActivate(int state, bool minimized, WXHWND activate) { - wxWindow::MSWOnActivate(state, minimized, activate); + wxWindow::MSWOnActivate(state, minimized, activate); // If this window is an MDI parent, we must also send an OnActivate message // to the current child. if ((m_currentChild != NULL) && ((state == WA_ACTIVE) || (state == WA_CLICKACTIVE))) - { + { wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_currentChild->GetId()); event.SetEventObject( m_currentChild ); m_currentChild->GetEventHandler()->ProcessEvent(event); @@ -467,7 +450,7 @@ bool wxMDIParentFrame::MSWOnCommand(WXWORD id, WXWORD cmd, WXHWND control) { return FALSE; // Get WndProc to call default proc } - + if (m_parentFrameActive && (id < wxFIRST_MDI_CHILD || id > wxLAST_MDI_CHILD)) { ProcessCommand(id); @@ -537,11 +520,11 @@ void wxMDIParentFrame::MSWOnMenuHighlight(WXWORD nItem, WXWORD nFlags, WXHMENU h long wxMDIParentFrame::MSWDefWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) { - WXHWND clientWnd; - if ( GetClientWindow() ) - clientWnd = GetClientWindow()->GetHWND(); - else - clientWnd = 0; + WXHWND clientWnd; + if ( GetClientWindow() ) + clientWnd = GetClientWindow()->GetHWND(); + else + clientWnd = 0; return DefFrameProc((HWND) GetHWND(), (HWND) clientWnd, message, wParam, lParam); } @@ -550,7 +533,7 @@ bool wxMDIParentFrame::MSWProcessMessage(WXMSG* msg) { if ((m_currentChild != (wxWindow *)NULL) && (m_currentChild->GetHWND() != (WXHWND) NULL) && m_currentChild->MSWProcessMessage(msg)) return TRUE; - + return FALSE; } @@ -560,7 +543,7 @@ bool wxMDIParentFrame::MSWTranslateMessage(WXMSG* msg) if ((m_currentChild != (wxWindow *)NULL) && (m_currentChild->GetHWND() != (WXHWND) NULL) && m_currentChild->MSWTranslateMessage(msg)) return TRUE; - + if (m_acceleratorTable.Ok() && ::TranslateAccelerator((HWND) GetHWND(), (HACCEL) m_acceleratorTable.GetHACCEL(), pMsg)) return TRUE; @@ -583,9 +566,9 @@ bool wxMDIParentFrame::MSWOnEraseBkgnd(WXHDC WXUNUSED(pDC)) extern wxWindow *wxWndHook; extern wxList *wxWinHandleList; -wxMDIChildFrame::wxMDIChildFrame(void) +wxMDIChildFrame::wxMDIChildFrame() { -// m_active = FALSE; +// m_active = FALSE; } bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, @@ -615,7 +598,7 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, int height = size.y; MDICREATESTRUCT mcs; - + mcs.szClass = wxMDIChildFrameClassName; mcs.szTitle = title; mcs.hOwner = wxGetInstance(); @@ -652,7 +635,7 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, mcs.lParam = 0; DWORD Return = SendMessage((HWND) parent->GetClientWindow()->GetHWND(), - WM_MDICREATE, 0, (LONG)(LPSTR)&mcs); + WM_MDICREATE, 0, (LONG)(LPSTR)&mcs); //handle = (HWND)LOWORD(Return); // Must be the DWORRD for WIN32. And in 16 bits, HIWORD=0 (says Microsoft) @@ -670,9 +653,9 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, return TRUE; } -wxMDIChildFrame::~wxMDIChildFrame(void) +wxMDIChildFrame::~wxMDIChildFrame() { - MSWDestroyWindow(); + MSWDestroyWindow(); ResetWindowStyle(NULL); } @@ -697,8 +680,8 @@ void wxMDIChildFrame::SetClientSize(int width, int height) if (GetStatusBar()) { - int sx, sy; - GetStatusBar()->GetSize(&sx, &sy); + int sx, sy; + GetStatusBar()->GetSize(&sx, &sy); actual_height += sy; } @@ -742,42 +725,25 @@ void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar) m_frameMenuBar = NULL; return; } - - if (menu_bar->m_menuBarFrame) - return; - int i; - HMENU menu = CreateMenu(); + if ( menu_bar->IsAttached() ) + return; - for (i = 0; i < menu_bar->m_menuCount; i ++) - { - HMENU popup = (HMENU)menu_bar->m_menus[i]->m_hMenu; - // - // After looking Bounds Checker result, it seems that all - // menus must be individually destroyed. So, don't reset m_hMenu, - // to allow ~wxMenu to do the job. - // - menu_bar->m_menus[i]->m_savehMenu = (WXHMENU) popup; - // Uncommenting for the moment... JACS - menu_bar->m_menus[i]->m_hMenu = 0; - ::AppendMenu((HMENU) menu, MF_POPUP | MF_STRING, (UINT)popup, menu_bar->m_titles[i]); - } + m_hMenu = menu_bar->Create(); - menu_bar->m_hMenu = (WXHMENU)menu; if (m_frameMenuBar) delete m_frameMenuBar; - this->m_hMenu = (WXHMENU) menu; - wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent(); parent->m_parentFrameActive = FALSE; HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0); // Try to insert Window menu in front of Help, otherwise append it. + HMENU menu = (HMENU)m_hMenu; int N = GetMenuItemCount(menu); bool success = FALSE; - for (i = 0; i < N; i++) + for (int i = 0; i < N; i++) { char buf[100]; int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION); @@ -805,25 +771,25 @@ void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar) DrawMenuBar((HWND) parent->GetHWND()); m_frameMenuBar = menu_bar; - menu_bar->m_menuBarFrame = this; + menu_bar->Attach(this); } // MDI operations -void wxMDIChildFrame::Maximize(void) +void wxMDIChildFrame::Maximize() { wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent(); if ( parent && parent->GetClientWindow() ) ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIMAXIMIZE, (WPARAM) (HWND) GetHWND(), 0); } -void wxMDIChildFrame::Restore(void) +void wxMDIChildFrame::Restore() { wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent(); if ( parent && parent->GetClientWindow() ) ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIRESTORE, (WPARAM) (HWND) GetHWND(), 0); } -void wxMDIChildFrame::Activate(void) +void wxMDIChildFrame::Activate() { wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent(); if ( parent && parent->GetClientWindow() ) @@ -839,7 +805,7 @@ void wxMDIChildFrame::MSWOnSize(int x, int y, WXUINT id) { return; } - + (void)MSWDefWindowProc(m_lastMsg, m_lastWParam, m_lastLParam); switch (id) @@ -991,7 +957,7 @@ long wxMDIChildFrame::MSWOnMDIActivate(long activate, WXHWND WXUNUSED(one), WXHW return 0; } -void wxMDIChildFrame::MSWDestroyWindow(void) +void wxMDIChildFrame::MSWDestroyWindow() { MSWDetachWindowMenu(); invalidHandle = (HWND) GetHWND(); @@ -1026,30 +992,30 @@ bool wxMDIChildFrame::ResetWindowStyle(void *vrect) { #if defined(__WIN95__) RECT *rect = (RECT *)vrect; - wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent(); - wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild(); - if (!pChild || (pChild == this)) - { - DWORD dwStyle = ::GetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE); + wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent(); + wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild(); + if (!pChild || (pChild == this)) + { + DWORD dwStyle = ::GetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE); DWORD dwThisStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE); - DWORD dwNewStyle = dwStyle; - if (pChild != NULL && (dwThisStyle & WS_MAXIMIZE)) - dwNewStyle &= ~(WS_EX_CLIENTEDGE); - else - dwNewStyle |= WS_EX_CLIENTEDGE; + DWORD dwNewStyle = dwStyle; + if (pChild != NULL && (dwThisStyle & WS_MAXIMIZE)) + dwNewStyle &= ~(WS_EX_CLIENTEDGE); + else + dwNewStyle |= WS_EX_CLIENTEDGE; - if (dwStyle != dwNewStyle) - { - ::RedrawWindow((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); - ::SetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE, dwNewStyle); - ::SetWindowPos((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, 0, 0, 0, 0, - SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS); - if (rect) - ::GetClientRect((HWND) pFrameWnd->GetClientWindow()->GetHWND(), rect); - return TRUE; - } - } - return FALSE; + if (dwStyle != dwNewStyle) + { + ::RedrawWindow((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); + ::SetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE, dwNewStyle); + ::SetWindowPos((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS); + if (rect) + ::GetClientRect((HWND) pFrameWnd->GetClientWindow()->GetHWND(), rect); + return TRUE; + } + } + return FALSE; #else return FALSE; #endif @@ -1060,36 +1026,36 @@ void wxMDIChildFrame::MSWOnWindowPosChanging(void *pos) WINDOWPOS *lpPos = (WINDOWPOS *)pos; #if defined(__WIN95__) if (!(lpPos->flags & SWP_NOSIZE)) - { - RECT rectClient; - DWORD dwExStyle = ::GetWindowLong((HWND) GetHWND(), GWL_EXSTYLE); + { + RECT rectClient; + DWORD dwExStyle = ::GetWindowLong((HWND) GetHWND(), GWL_EXSTYLE); DWORD dwStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE); - if (ResetWindowStyle((void *) & rectClient) && (dwStyle & WS_MAXIMIZE)) - { - ::AdjustWindowRectEx(&rectClient, dwStyle, FALSE, dwExStyle); - lpPos->x = rectClient.left; + if (ResetWindowStyle((void *) & rectClient) && (dwStyle & WS_MAXIMIZE)) + { + ::AdjustWindowRectEx(&rectClient, dwStyle, FALSE, dwExStyle); + lpPos->x = rectClient.left; lpPos->y = rectClient.top; - lpPos->cx = rectClient.right - rectClient.left; + lpPos->cx = rectClient.right - rectClient.left; lpPos->cy = rectClient.bottom - rectClient.top; - } - wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent(); + } + wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent(); if (pFrameWnd && pFrameWnd->GetToolBar()) { pFrameWnd->GetToolBar()->Refresh(); } - } + } #endif Default(); } // Client window -wxMDIClientWindow::wxMDIClientWindow(void) +wxMDIClientWindow::wxMDIClientWindow() { m_scrollX = 0; m_scrollY = 0; } -wxMDIClientWindow::~wxMDIClientWindow(void) +wxMDIClientWindow::~wxMDIClientWindow() { } @@ -1100,15 +1066,15 @@ bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style) CLIENTCREATESTRUCT ccs; m_windowStyle = style; m_windowParent = parent; - + ccs.hWindowMenu = (HMENU) parent->GetWindowMenu(); ccs.idFirstChild = wxFIRST_MDI_CHILD; DWORD msStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN ; if ( parent->GetWindowStyleFlag() & wxHSCROLL ) - msStyle |= WS_HSCROLL; + msStyle |= WS_HSCROLL; if ( parent->GetWindowStyleFlag() & wxVSCROLL ) - msStyle |= WS_VSCROLL ; + msStyle |= WS_VSCROLL ; #if defined(__WIN95__) DWORD exStyle = WS_EX_CLIENTEDGE; @@ -1135,10 +1101,10 @@ long wxMDIClientWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPa long wxMDIClientWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { - if ( MSWGetOldWndProc() != 0) - return ::CallWindowProc(CASTWNDPROC MSWGetOldWndProc(), (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); - else - return ::DefWindowProc((HWND) m_hWnd, (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); + if ( MSWGetOldWndProc() != 0) + return ::CallWindowProc(CASTWNDPROC MSWGetOldWndProc(), (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); + else + return ::DefWindowProc((HWND) m_hWnd, (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); } // Explicitly call default scroll behaviour @@ -1155,7 +1121,7 @@ void wxMDIClientWindow::OnScroll(wxScrollEvent& event) else m_scrollY = event.GetPosition(); // Always returns zero! - Default(); + Default(); } // Should hand the message to the default proc diff --git a/src/msw/menu.cpp b/src/msw/menu.cpp index 2b0223238f..14d738290c 100644 --- a/src/msw/menu.cpp +++ b/src/msw/menu.cpp @@ -9,6 +9,14 @@ // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + #ifdef __GNUG__ #pragma implementation "menu.h" #endif @@ -60,7 +68,7 @@ static const int idMenuTitle = -2; IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler) #endif -// convenience macro +// convenience macros #define GetHMENU() ((HMENU)GetHMenu()) #define GetHMenuOf(menu) ((HMENU)menu->GetHMenu()) @@ -68,7 +76,9 @@ static const int idMenuTitle = -2; // implementation // ============================================================================ -// Menus +// --------------------------------------------------------------------------- +// wxMenu construction, adding and removing menu items +// --------------------------------------------------------------------------- // Construct a menu with optional title (then use append) wxMenu::wxMenu(const wxString& title, const wxFunction func) @@ -91,46 +101,31 @@ wxMenu::wxMenu(const wxString& title, const wxFunction func) AppendSeparator() ; } +#if WXWIN_COMPATIBILITY Callback(func); +#endif } // The wxWindow destructor will take care of deleting the submenus. wxMenu::~wxMenu() { - if (m_hMenu) - DestroyMenu((HMENU) m_hMenu); - m_hMenu = 0; + // free Windows resources + if ( m_hMenu ) + { + ::DestroyMenu((HMENU)m_hMenu); + m_hMenu = 0; + } - // Windows seems really bad on Menu de-allocation... - // After many try, here is what I do: RemoveMenu() will ensure - // that popup are "disconnected" from their parent; then call - // delete method on each child (which in turn do a recursive job), - // and finally, DestroyMenu() - // - // With that, BoundCheckers is happy, and no complaints... - /* - int N = 0 ; - if (m_hMenu) - N = GetMenuItemCount(m_hMenu); - int i; - for (i = N-1; i >= 0; i--) - RemoveMenu(m_hMenu, i, MF_BYPOSITION); - */ - - // How is deleting submenus in this loop any different from deleting - // the submenus in the children list, via ~wxWindow ? - // I'll reinstate this deletion for now and remove addition - // from children list (which doesn't exist now) - // Julian 1/3/97 + // delete submenus wxNode *node = m_menuItems.First(); - while (node) + while ( node ) { wxMenuItem *item = (wxMenuItem *)node->Data(); // Delete child menus. // Beware: they must not be appended to children list!!! // (because order of delete is significant) - if (item->GetSubMenu()) + if ( item->IsSubMenu() ) item->DeleteSubMenu(); wxNode *next = node->Next(); @@ -138,16 +133,11 @@ wxMenu::~wxMenu() delete node; node = next; } - /* - if (m_hMenu) - DestroyMenu(m_hMenu); - m_hMenu = 0; - */ } void wxMenu::Break() { - m_doBreak = TRUE ; + m_doBreak = TRUE; } // function appends a new item or submenu to the menu @@ -155,10 +145,10 @@ void wxMenu::Append(wxMenuItem *pItem) { wxCHECK_RET( pItem != NULL, "can't append NULL item to the menu" ); - m_menuItems.Append(pItem); - UINT flags = 0; + // if "Break" has just been called, insert a menu break before this item + // (and don't forget to reset the flag) if ( m_doBreak ) { flags |= MF_MENUBREAK; m_doBreak = FALSE; @@ -168,18 +158,18 @@ void wxMenu::Append(wxMenuItem *pItem) flags |= MF_SEPARATOR; } - // id is the numeric id for normal menu items and HMENU for submenus + // id is the numeric id for normal menu items and HMENU for submenus as + // required by ::AppendMenu() API UINT id; - wxMenu *SubMenu = pItem->GetSubMenu(); - if ( SubMenu != NULL ) { - wxASSERT( SubMenu->m_hMenu != (WXHMENU) NULL ); + wxMenu *submenu = pItem->GetSubMenu(); + if ( submenu != NULL ) { + wxASSERT( submenu->GetHMenu() != (WXHMENU) NULL ); - id = (UINT)SubMenu->m_hMenu; - - SubMenu->m_topLevelMenu = m_topLevelMenu; - SubMenu->m_parent = this; - SubMenu->m_savehMenu = (WXHMENU)id; - SubMenu->m_hMenu = 0; + id = (UINT)submenu->GetHMenu(); + submenu->m_topLevelMenu = m_topLevelMenu; + submenu->m_parent = this; + submenu->m_savehMenu = (WXHMENU)id; + submenu->m_hMenu = 0; flags |= MF_POPUP; } @@ -209,12 +199,15 @@ void wxMenu::Append(wxMenuItem *pItem) // TODO use SetMenuItemInfo(MFS_DEFAULT) to put it in bold face } - if ( !AppendMenu(GetHMENU(), flags, id, pData) ) + if ( !::AppendMenu(GetHMENU(), flags, id, pData) ) { wxLogLastError("AppendMenu"); } - - m_noItems++; + else + { + m_menuItems.Append(pItem); + m_noItems++; + } } void wxMenu::AppendSeparator() @@ -223,20 +216,25 @@ void wxMenu::AppendSeparator() } // Pullright item -void wxMenu::Append(int id, const wxString& label, - wxMenu *SubMenu, const wxString& helpString) +void wxMenu::Append(int id, + const wxString& label, + wxMenu *SubMenu, + const wxString& helpString) { Append(new wxMenuItem(this, id, label, helpString, FALSE, SubMenu)); } // Ordinary menu item -void wxMenu::Append(int id, const wxString& label, - const wxString& helpString, bool checkable) +void wxMenu::Append(int id, + const wxString& label, + const wxString& helpString, + bool checkable) { // 'checkable' parameter is useless for Windows. Append(new wxMenuItem(this, id, label, helpString, checkable)); } +// delete item by id void wxMenu::Delete(int id) { wxMenuItem *item = NULL; @@ -274,6 +272,10 @@ void wxMenu::Delete(int id) delete item; } +// --------------------------------------------------------------------------- +// wxMenu functions implemented in wxMenuItem +// --------------------------------------------------------------------------- + void wxMenu::Enable(int id, bool Flag) { wxMenuItem *item = FindItemForId(id); @@ -306,6 +308,51 @@ bool wxMenu::IsChecked(int id) const return item->IsChecked(); } +void wxMenu::SetLabel(int id, const wxString& label) +{ + wxMenuItem *item = FindItemForId(id) ; + wxCHECK_RET( item, "wxMenu::SetLabel: no such item" ); + + item->SetName(label); +} + +wxString wxMenu::GetLabel(int id) const +{ + wxString label; + wxMenuItem *pItem = FindItemForId(id) ; + if (pItem) + label = pItem->GetName() ; + else + wxFAIL_MSG("wxMenu::GetLabel: item doesn't exist"); + + return label; +} + +void wxMenu::SetHelpString(int itemId, const wxString& helpString) +{ + wxMenuItem *item = FindItemForId (itemId); + if (item) + item->SetHelp(helpString); + else + wxFAIL_MSG("wxMenu::SetHelpString: item doesn't exist"); +} + +wxString wxMenu::GetHelpString (int itemId) const +{ + wxString help; + wxMenuItem *item = FindItemForId (itemId); + if (item) + help = item->GetHelp(); + else + wxFAIL_MSG("wxMenu::GetHelpString: item doesn't exist"); + + return help; +} + +// --------------------------------------------------------------------------- +// wxMenu title +// --------------------------------------------------------------------------- + void wxMenu::SetTitle(const wxString& label) { bool hasNoTitle = m_title.IsEmpty(); @@ -370,51 +417,9 @@ const wxString wxMenu::GetTitle() const return m_title; } -void wxMenu::SetLabel(int id, const wxString& label) -{ - wxMenuItem *item = FindItemForId(id) ; - if (item==NULL) - return; - - if (item->GetSubMenu()==NULL) - { - HMENU hMenu = GetHMENU(); - - UINT was_flag = GetMenuState(hMenu, id, MF_BYCOMMAND); - ModifyMenu(hMenu, id, MF_BYCOMMAND | MF_STRING | was_flag, id, label); - } - else - { - wxMenu *father = item->GetSubMenu()->m_topLevelMenu ; - wxNode *node = father->m_menuItems.First() ; - int i = 0 ; - while (node) - { - wxMenuItem *matched = (wxMenuItem*)node->Data() ; - if (matched==item) - break ; - i++ ; - node = node->Next() ; - } - // Here, we have the position. - ModifyMenu((HMENU)father->m_savehMenu,i, - MF_BYPOSITION|MF_STRING|MF_POPUP, - (UINT)item->GetSubMenu()->m_savehMenu,(const char *)label) ; - } - item->SetName(label); -} - -wxString wxMenu::GetLabel(int id) const -{ - wxString label; - wxMenuItem *pItem = FindItemForId(id) ; - if (pItem) - label = pItem->GetName() ; - else - wxFAIL_MSG("wxMenu::GetLabel: item doesn't exist"); - - return label; -} +// --------------------------------------------------------------------------- +// event processing +// --------------------------------------------------------------------------- bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id) { @@ -433,83 +438,6 @@ bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id) return TRUE; } -// Finds the item id matching the given string, -1 if not found. -int wxMenu::FindItem (const wxString& itemString) const -{ - // FIXME fixed size buffer - char buf1[200]; - char buf2[200]; - wxStripMenuCodes ((char *)(const char *)itemString, buf1); - - for (wxNode * node = m_menuItems.First (); node; node = node->Next ()) - { - wxMenuItem *item = (wxMenuItem *) node->Data (); - if (item->GetSubMenu()) - { - int ans = item->GetSubMenu()->FindItem(itemString); - if (ans > -1) - return ans; - } - if ( !item->IsSeparator() ) - { - wxStripMenuCodes((char *)item->GetName().c_str(), buf2); - if (strcmp(buf1, buf2) == 0) - return item->GetId(); - } - } - - return wxNOT_FOUND; -} - -wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const -{ - if (itemMenu) - *itemMenu = NULL; - for (wxNode * node = m_menuItems.First (); node; node = node->Next ()) - { - wxMenuItem *item = (wxMenuItem *) node->Data (); - - if (item->GetId() == itemId) - { - if (itemMenu) - *itemMenu = (wxMenu *) this; - return item; - } - - if (item->GetSubMenu()) - { - wxMenuItem *ans = item->GetSubMenu()->FindItemForId (itemId, itemMenu); - if (ans) - return ans; - } - } - - if (itemMenu) - *itemMenu = NULL; - return NULL; -} - -void wxMenu::SetHelpString(int itemId, const wxString& helpString) -{ - wxMenuItem *item = FindItemForId (itemId); - if (item) - item->SetHelp(helpString); - else - wxFAIL_MSG("wxMenu::SetHelpString: item doesn't exist"); -} - -wxString wxMenu::GetHelpString (int itemId) const -{ - wxString help; - wxMenuItem *item = FindItemForId (itemId); - if (item) - help = item->GetHelp(); - else - wxFAIL_MSG("wxMenu::GetHelpString: item doesn't exist"); - - return help; -} - void wxMenu::ProcessCommand(wxCommandEvent & event) { bool processed = FALSE; @@ -534,13 +462,73 @@ void wxMenu::ProcessCommand(wxCommandEvent & event) processed = win->GetEventHandler()->ProcessEvent(event); } +// --------------------------------------------------------------------------- +// Item search +// --------------------------------------------------------------------------- + +// Finds the item id matching the given string, -1 if not found. +int wxMenu::FindItem (const wxString& itemString) const +{ + // FIXME fixed size buffer + wxString itemLabel = wxStripMenuCodes(itemString); + for ( wxNode *node = m_menuItems.First(); node; node = node->Next() ) + { + wxMenuItem *item = (wxMenuItem *)node->Data(); + if ( item->IsSubMenu() ) + { + int ans = item->GetSubMenu()->FindItem(itemString); + if ( ans != wxNOT_FOUND ) + return ans; + } + else if ( !item->IsSeparator() ) + { + wxString label = wxStripMenuCodes(item->GetName()); + if ( itemLabel == label ) + return item->GetId(); + } + } + + return wxNOT_FOUND; +} + +wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const +{ + if ( itemMenu ) + *itemMenu = NULL; + + wxMenuItem *item = NULL; + for ( wxNode *node = m_menuItems.First(); node; node = node->Next() ) + { + item = (wxMenuItem *)node->Data(); + + if ( item->GetId() == itemId ) + { + if (itemMenu) + *itemMenu = (wxMenu *)this; + break; + } + else if ( item->IsSubMenu() ) + { + item = item->GetSubMenu()->FindItemForId(itemId, itemMenu); + if ( item ) + break; + } + } + + return item; +} + +// --------------------------------------------------------------------------- +// other +// --------------------------------------------------------------------------- + bool wxWindow::PopupMenu(wxMenu *menu, int x, int y) { menu->SetInvokingWindow(this); menu->UpdateUI(); HWND hWnd = (HWND) GetHWND(); - HMENU hMenu = (HMENU)menu->m_hMenu; + HMENU hMenu = (HMENU)menu->GetHMenu(); POINT point; point.x = x; point.y = y; @@ -555,8 +543,30 @@ bool wxWindow::PopupMenu(wxMenu *menu, int x, int y) return TRUE; } +void wxMenu::Attach(wxMenuBar *menubar) +{ + // menu can be in at most one menubar because otherwise they would both + // delete the menu pointer + wxASSERT_MSG( !m_menuBar, "menu belongs to 2 menubars, expect a crash" ); + + m_menuBar = menubar; + m_savehMenu = m_hMenu; + m_hMenu = 0; +} + +void wxMenu::Detach() +{ + wxASSERT_MSG( m_menuBar, "can't detach menu if it's not attached" ); + + m_hMenu = m_savehMenu; + m_savehMenu = 0; +} + +// --------------------------------------------------------------------------- // Menu Bar -wxMenuBar::wxMenuBar() +// --------------------------------------------------------------------------- + +void wxMenuBar::Init() { m_eventHandler = this; m_menuCount = 0; @@ -566,83 +576,94 @@ wxMenuBar::wxMenuBar() m_hMenu = 0; } +wxMenuBar::wxMenuBar() +{ + Init(); +} + wxMenuBar::wxMenuBar( long WXUNUSED(style) ) { - m_eventHandler = this; - m_menuCount = 0; - m_menus = NULL; - m_titles = NULL; - m_menuBarFrame = NULL; - m_hMenu = 0; + Init(); } -wxMenuBar::wxMenuBar(int N, wxMenu *Menus[], const wxString Titles[]) +wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[]) { - m_eventHandler = this; - m_menuCount = N; - m_menus = Menus; - m_titles = new wxString[N]; - int i; - for ( i = 0; i < N; i++ ) - m_titles[i] = Titles[i]; - m_menuBarFrame = NULL; - for (i = 0; i < N; i++) - m_menus[i]->m_menuBar = (wxMenuBar *) this; + Init(); - m_hMenu = 0; + m_menuCount = count; + m_menus = menus; + m_titles = new wxString[count]; + + int i; + for ( i = 0; i < count; i++ ) + m_titles[i] = titles[i]; + + for ( i = 0; i < count; i++ ) + m_menus[i]->Attach(this); } wxMenuBar::~wxMenuBar() { - // In fact, don't want menu to be destroyed before MDI - // shuffling has taken place. Let it be destroyed - // automatically when the window is destroyed. - - // DestroyMenu(menu); - // m_hMenu = NULL; - - int i; - /* - // See remarks in ::~wxMenu() method - // BEWARE - this may interfere with MDI fixes, so - // may need to remove - int N = 0 ; - - if (m_menuBarFrame && ((m_menuBarFrame->GetWindowStyleFlag() & wxSDI) == wxSDI)) - { - if (menu) - N = GetMenuItemCount(menu) ; - for (i = N-1; i >= 0; i--) - RemoveMenu(menu, i, MF_BYPOSITION); - } - */ - for (i = 0; i < m_menuCount; i++) + for ( int i = 0; i < m_menuCount; i++ ) { delete m_menus[i]; } + delete[] m_menus; delete[] m_titles; - - /* Don't destroy menu here, in case we're MDI and - need to do some shuffling with VALID menu handles. - if (menu) - DestroyMenu(menu); - m_hMenu = 0; - */ } +// --------------------------------------------------------------------------- +// wxMenuBar helpers +// --------------------------------------------------------------------------- + +void wxMenuBar::Refresh() +{ + wxCHECK_RET( m_menuBarFrame, "can't refresh a menubar withotu a frame" ); + + DrawMenuBar((HWND)m_menuBarFrame->GetHWND()) ; +} + +WXHMENU wxMenuBar::Create() +{ + wxCHECK_MSG( !m_hMenu, TRUE, "menubar already created" ); + + m_hMenu = (WXHMENU)::CreateMenu(); + + if ( !m_hMenu ) + { + wxLogLastError("CreateMenu"); + } + else + { + for ( int i = 0; i < m_menuCount; i++ ) + { + if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, + (UINT)m_menus[i]->GetHMenu(), + m_titles[i]) ) + { + wxLogLastError("AppendMenu"); + } + } + } + + return m_hMenu; +} + +// --------------------------------------------------------------------------- +// wxMenuBar functions forwarded to wxMenuItem +// --------------------------------------------------------------------------- + // Must only be used AFTER menu has been attached to frame, // otherwise use individual menus to enable/disable items void wxMenuBar::Enable(int id, bool enable) { - int flag = enable ? MF_ENABLED : MF_GRAYED; - wxMenu *itemMenu = NULL; wxMenuItem *item = FindItemForId(id, &itemMenu) ; wxCHECK_RET( item, "attempt to enable an item which doesn't exist" ); - EnableMenuItem(GetHMenuOf(itemMenu), id, MF_BYCOMMAND | flag); + item->Enable(enable); } void wxMenuBar::EnableTop(int pos, bool enable) @@ -650,7 +671,6 @@ void wxMenuBar::EnableTop(int pos, bool enable) int flag = enable ? MF_ENABLED : MF_GRAYED;; EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag); - DrawMenuBar((HWND)m_menuBarFrame->GetHWND()) ; } // Must only be used AFTER menu has been attached to frame, @@ -663,8 +683,7 @@ void wxMenuBar::Check(int id, bool check) wxCHECK_RET( item, "attempt to check an item which doesn't exist" ); wxCHECK_RET( item->IsCheckable(), "attempt to check an uncheckable item" ); - int flag = check ? MF_CHECKED : MF_UNCHECKED; - CheckMenuItem(GetHMenuOf(itemMenu), id, MF_BYCOMMAND | flag); + item->Check(check); } bool wxMenuBar::IsChecked(int id) const @@ -672,7 +691,7 @@ bool wxMenuBar::IsChecked(int id) const wxMenu *itemMenu = NULL; wxMenuItem *item = FindItemForId(id, &itemMenu) ; - wxCHECK_MSG( item, FALSE, "wxMenuItem::IsChecked(): no such item" ); + wxCHECK_MSG( item, FALSE, "wxMenuBar::IsChecked(): no such item" ); int flag = ::GetMenuState(GetHMenuOf(itemMenu), id, MF_BYCOMMAND); @@ -684,7 +703,7 @@ bool wxMenuBar::IsEnabled(int id) const wxMenu *itemMenu = NULL; wxMenuItem *item = FindItemForId(id, &itemMenu) ; - wxCHECK_MSG( item, FALSE, "wxMenuItem::IsEnabled(): no such item" ); + wxCHECK_MSG( item, FALSE, "wxMenuBar::IsEnabled(): no such item" ); int flag = ::GetMenuState(GetHMenuOf(itemMenu), id, MF_BYCOMMAND) ; @@ -696,12 +715,9 @@ void wxMenuBar::SetLabel(int id, const wxString& label) wxMenu *itemMenu = NULL; wxMenuItem *item = FindItemForId(id, &itemMenu) ; - if (!item) - return; + wxCHECK_RET( item, "wxMenuBar::SetLabel(): no such item" ); - HMENU hMenu = GetHMenuOf(itemMenu); - UINT was_flag = ::GetMenuState(hMenu, id, MF_BYCOMMAND); - ::ModifyMenu(hMenu, id, MF_BYCOMMAND | MF_STRING | was_flag, id, label); + item->SetName(label); } wxString wxMenuBar::GetLabel(int id) const @@ -709,26 +725,53 @@ wxString wxMenuBar::GetLabel(int id) const wxMenu *itemMenu = NULL; wxMenuItem *item = FindItemForId(id, &itemMenu) ; - wxCHECK_MSG( item, "", "wxMenuItem::GetLabel(): no such item" ); + wxCHECK_MSG( item, "", "wxMenuBar::GetLabel(): no such item" ); - HMENU hMenu = GetHMenuOf(itemMenu); - int len = ::GetMenuString(hMenu, id, NULL, 0, MF_BYCOMMAND); - - len++; // for the NUL character - wxString label; - ::GetMenuString(hMenu, id, label.GetWriteBuf(len), len, MF_BYCOMMAND); - label.UngetWriteBuf(); - - return label; + return item->GetName(); } +void wxMenuBar::SetHelpString (int id, const wxString& helpString) +{ + wxMenu *itemMenu = NULL; + wxMenuItem *item = FindItemForId(id, &itemMenu) ; + + wxCHECK_RET( item, "wxMenuBar::SetHelpString(): no such item" ); + + item->SetHelp(helpString); +} + +wxString wxMenuBar::GetHelpString (int id) const +{ + wxMenu *itemMenu = NULL; + wxMenuItem *item = FindItemForId(id, &itemMenu) ; + + wxCHECK_MSG( item, "", "wxMenuBar::GetHelpString(): no such item" ); + + return item->GetHelp(); +} + +// --------------------------------------------------------------------------- +// wxMenuBar functions to work with the top level submenus +// --------------------------------------------------------------------------- + +// NB: we don't support owner drawn top level items for now, if we do these +// functions would have to be changed to use wxMenuItem as well + void wxMenuBar::SetLabelTop(int pos, const wxString& label) { UINT id; - UINT was_flag = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION); - if (was_flag & MF_POPUP) + UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION); + if ( flagsOld == 0xFFFFFFFF ) { - was_flag &= 0xff ; + wxLogLastError("GetMenuState"); + + return; + } + + if ( flagsOld & MF_POPUP ) + { + // HIBYTE contains the number of items in the submenu in this case + flagsOld &= 0xff ; id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos) ; } else @@ -736,8 +779,11 @@ void wxMenuBar::SetLabelTop(int pos, const wxString& label) id = pos; } - ::ModifyMenu((HMENU)m_hMenu, pos, MF_BYPOSITION | MF_STRING | was_flag, - id, label) ; + if ( ::ModifyMenu(GetHMENU(), pos, MF_BYPOSITION | MF_STRING | flagsOld, + id, label) == 0xFFFFFFFF ) + { + wxLogLastError("ModifyMenu"); + } } wxString wxMenuBar::GetLabelTop(int pos) const @@ -746,49 +792,67 @@ wxString wxMenuBar::GetLabelTop(int pos) const len++; // for the NUL character wxString label; - ::GetMenuString((HMENU)m_hMenu, pos, label.GetWriteBuf(len), len, MF_BYCOMMAND); + ::GetMenuString(GetHMENU(), pos, label.GetWriteBuf(len), len, MF_BYCOMMAND); label.UngetWriteBuf(); return label; } +// --------------------------------------------------------------------------- +// wxMenuBar notifications +// --------------------------------------------------------------------------- + bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos) { - if (!m_menuBarFrame) + if ( !m_menuBarFrame ) return TRUE; - if (RemoveMenu((HMENU)m_hMenu, (UINT)pos, MF_BYPOSITION)) { - m_menus[pos]->m_hMenu = m_menus[pos]->m_savehMenu; - m_menus[pos]->m_savehMenu = 0; + if ( ::RemoveMenu((HMENU)m_hMenu, (UINT)pos, MF_BYPOSITION) ) + { + // VZ: I'm not sure about what's going on here, so I leave an assert + wxASSERT_MSG( m_menus[pos] == a_menu, "what is this parameter for??" ); - if (m_menuBarFrame) { - DrawMenuBar((HWND) m_menuBarFrame->GetHWND()) ; - } + a_menu->Detach(); + + if ( m_menuBarFrame ) + Refresh(); return TRUE; } + else + { + wxLogLastError("RemoveMenu"); + } return FALSE; } bool wxMenuBar::OnAppend(wxMenu *a_menu, const char *title) { - if (!a_menu->m_hMenu) + WXHMENU submenu = a_menu->GetHMenu(); + if ( !submenu ) return FALSE; - if (!m_menuBarFrame) + if ( !m_menuBarFrame ) return TRUE; - a_menu->m_savehMenu = a_menu->m_hMenu; - a_menu->m_hMenu = 0; + a_menu->Attach(this); - AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, (UINT)a_menu->m_savehMenu, title); + if ( !::AppendMenu(GetHMENU(), MF_POPUP | MF_STRING, + (UINT)submenu, title) ) + { + wxLogLastError("AppendMenu"); + } - DrawMenuBar((HWND)m_menuBarFrame->GetHWND()); + Refresh(); return TRUE; } +// --------------------------------------------------------------------------- +// wxMenuBar construction +// --------------------------------------------------------------------------- + void wxMenuBar::Append (wxMenu * menu, const wxString& title) { if (!OnAppend(menu, title)) @@ -817,8 +881,7 @@ void wxMenuBar::Append (wxMenu * menu, const wxString& title) m_menus[m_menuCount - 1] = (wxMenu *)menu; m_titles[m_menuCount - 1] = title; - ((wxMenu *)menu)->m_menuBar = (wxMenuBar *) this; - ((wxMenu *)menu)->SetParent(this); + menu->SetParent(this); } void wxMenuBar::Delete(wxMenu * menu, int i) @@ -851,70 +914,40 @@ void wxMenuBar::Delete(wxMenu * menu, int i) } } -// Find the menu menuString, item itemString, and return the item id. -// Returns -1 if none found. -int wxMenuBar::FindMenuItem (const wxString& menuString, const wxString& itemString) const +// --------------------------------------------------------------------------- +// wxMenuBar searching for menu items +// --------------------------------------------------------------------------- + +// Find the itemString in menuString, and return the item id or wxNOT_FOUND +int wxMenuBar::FindMenuItem(const wxString& menuString, + const wxString& itemString) const { - char buf1[200]; - char buf2[200]; - wxStripMenuCodes ((char *)(const char *)menuString, buf1); - int i; - for (i = 0; i < m_menuCount; i++) + wxString menuLabel = wxStripMenuCodes(menuString); + for ( int i = 0; i < m_menuCount; i++ ) { - wxStripMenuCodes ((char *)(const char *)m_titles[i], buf2); - if (strcmp (buf1, buf2) == 0) - return m_menus[i]->FindItem (itemString); + wxString title = wxStripMenuCodes(m_titles[i]); + if ( menuString == title ) + return m_menus[i]->FindItem(itemString); } - return -1; + + return wxNOT_FOUND; } -wxMenuItem *wxMenuBar::FindItemForId (int id, wxMenu ** itemMenu) const +wxMenuItem *wxMenuBar::FindItemForId (int id, wxMenu **itemMenu) const { - if (itemMenu) + if ( itemMenu ) *itemMenu = NULL; wxMenuItem *item = NULL; - int i; - for (i = 0; i < m_menuCount; i++) + for ( int i = 0; !item && (i < m_menuCount); i++ ) { - item = m_menus[i]->FindItemForId (id, itemMenu); - if (item) - return item; - } - return NULL; -} - -void wxMenuBar::SetHelpString (int id, const wxString& helpString) -{ - int i; - for (i = 0; i < m_menuCount; i++) - { - if (m_menus[i]->FindItemForId (id)) - { - m_menus[i]->SetHelpString (id, helpString); - return; - } - } -} - -wxString wxMenuBar::GetHelpString (int id) const -{ - wxString helpString; - - for (int i = 0; i < m_menuCount; i++) - { - wxMenuItem *item = m_menus[i]->FindItemForId(id); - if ( item ) - { - helpString = item->GetHelp(); - - break; - } + item = m_menus[i]->FindItemForId(id, itemMenu); } - return helpString; + return item; } + // ---------------------------------------------------------------------------- // helper functions // ---------------------------------------------------------------------------- @@ -924,7 +957,7 @@ wxWindow *wxMenu::GetWindow() const if ( m_pInvokingWindow != NULL ) return m_pInvokingWindow; else if ( m_menuBar != NULL) - return m_menuBar->m_menuBarFrame; + return m_menuBar->GetFrame(); return NULL; } diff --git a/src/msw/menuitem.cpp b/src/msw/menuitem.cpp index 916819d272..e5a55c54a9 100644 --- a/src/msw/menuitem.cpp +++ b/src/msw/menuitem.cpp @@ -2,30 +2,38 @@ // Name: menuitem.cpp // Purpose: wxMenuItem implementation // Author: Vadim Zeitlin -// Modified by: +// Modified by: // Created: 11.11.97 // RCS-ID: $Id$ // Copyright: (c) 1998 Vadim Zeitlin // Licence: wxWindows license /////////////////////////////////////////////////////////////////////////////// +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + #ifdef __GNUG__ -#pragma implementation "menuitem.h" + #pragma implementation "menuitem.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif #ifndef WX_PRECOMP -#include "wx/menu.h" -#include "wx/font.h" -#include "wx/bitmap.h" -#include "wx/settings.h" -#include "wx/font.h" + #include "wx/menu.h" + #include "wx/font.h" + #include "wx/bitmap.h" + #include "wx/settings.h" + #include "wx/font.h" #endif #include "wx/ownerdrw.h" @@ -34,13 +42,19 @@ #include #ifdef GetClassInfo -#undef GetClassInfo + #undef GetClassInfo #endif #ifdef GetClassName -#undef GetClassName + #undef GetClassName #endif +// --------------------------------------------------------------------------- +// convenience macro +// --------------------------------------------------------------------------- + +#define GetHMenuOf(menu) ((HMENU)menu->GetHMenu()) + // ============================================================================ // implementation // ============================================================================ @@ -77,12 +91,12 @@ wxMenuItem::wxMenuItem(wxMenu *pParentMenu, int id, #endif //owner drawn m_strHelp(strHelp) { - wxASSERT( pParentMenu != NULL ); + wxASSERT_MSG( pParentMenu != NULL, "a menu item should have a parent" ); #if wxUSE_OWNER_DRAWN // set default menu colors #define SYS_COLOR(c) (wxSystemSettings::GetSystemColour(wxSYS_COLOUR_##c)) - + SetTextColour(SYS_COLOR(MENUTEXT)); SetBackgroundColour(SYS_COLOR(MENU)); @@ -92,26 +106,31 @@ wxMenuItem::wxMenuItem(wxMenu *pParentMenu, int id, #undef SYS_COLOR #endif - m_pParentMenu = pParentMenu; - m_pSubMenu = pSubMenu; - m_idItem = id; - m_bEnabled = TRUE; + m_pParentMenu = pParentMenu; + m_pSubMenu = pSubMenu; + m_bEnabled = TRUE; + m_idItem = id; } -wxMenuItem::~wxMenuItem() +wxMenuItem::~wxMenuItem() { } // misc // ---- +// return the id for calling Win32 API functions +int wxMenuItem::GetRealId() const +{ + return m_pSubMenu ? (int)m_pSubMenu->GetHMenu() : GetId(); +} + // delete the sub menu +// ------------------- void wxMenuItem::DeleteSubMenu() { - wxASSERT( m_pSubMenu != NULL ); - - delete m_pSubMenu; - m_pSubMenu = NULL; + delete m_pSubMenu; + m_pSubMenu = NULL; } // change item state @@ -119,39 +138,83 @@ void wxMenuItem::DeleteSubMenu() void wxMenuItem::Enable(bool bDoEnable) { - if ( m_bEnabled != bDoEnable ) { - if ( m_pSubMenu == NULL ) { // normal menu item - EnableMenuItem((HMENU)m_pParentMenu->GetHMenu(), m_idItem, - MF_BYCOMMAND | (bDoEnable ? MF_ENABLED: MF_GRAYED)); - } - else // submenu - { - wxMenu *father = m_pSubMenu->m_topLevelMenu ; - wxNode *node = father->m_menuItems.First() ; - int i = 0 ; - while (node) { - wxMenuItem *matched = (wxMenuItem*)node->Data(); - if ( matched == this) - break; - i++; - node = node->Next(); - } - EnableMenuItem((HMENU)father->m_savehMenu, i, - MF_BYPOSITION | (bDoEnable ? MF_ENABLED: MF_GRAYED)); - } + if ( m_bEnabled != bDoEnable ) { + long rc = EnableMenuItem(GetHMenuOf(m_pParentMenu), + GetRealId(), + MF_BYCOMMAND | + (bDoEnable ? MF_ENABLED : MF_GRAYED)); - m_bEnabled = bDoEnable; - } + if ( rc == -1 ) { + wxLogLastError("EnableMenuItem"); + } + + m_bEnabled = bDoEnable; + } } void wxMenuItem::Check(bool bDoCheck) { - wxCHECK_RET( IsCheckable(), "only checkable items may be checked" ); + wxCHECK_RET( IsCheckable(), "only checkable items may be checked" ); - if ( m_bChecked != bDoCheck ) { - CheckMenuItem((HMENU)m_pParentMenu->GetHMenu(), m_idItem, - MF_BYCOMMAND | (bDoCheck ? MF_CHECKED : MF_UNCHECKED)); + if ( m_bChecked != bDoCheck ) { + long rc = CheckMenuItem(GetHMenuOf(m_pParentMenu), + GetId(), + MF_BYCOMMAND | + (bDoCheck ? MF_CHECKED : MF_UNCHECKED)); + + if ( rc == -1 ) { + wxLogLastError("CheckMenuItem"); + } + + m_bChecked = bDoCheck; + } +} + +void wxMenuItem::SetName(const wxString& strName) +{ + // don't do anything if label didn't change + if ( m_strName == strName ) + return; + + m_strName = strName; + + HMENU hMenu = GetHMenuOf(m_pParentMenu); + + UINT id = GetRealId(); + UINT flagsOld = ::GetMenuState(hMenu, id, MF_BYCOMMAND); + if ( flagsOld == 0xFFFFFFFF ) + { + wxLogLastError("GetMenuState"); + } + else + { + if ( IsSubMenu() ) + { + // high byte contains the number of items in a submenu for submenus + flagsOld &= 0xFF; + flagsOld |= MF_POPUP; + } + + LPCSTR data; +#if wxUSE_OWNER_DRAWN + if ( IsOwnerDrawn() ) + { + flagsOld |= MF_OWNERDRAW; + data = (LPCSTR)this; + } + else +#endif //owner drawn + { + flagsOld |= MF_STRING; + data = strName; + } + + if ( ::ModifyMenu(hMenu, id, + MF_BYCOMMAND | flagsOld, + id, data) == 0xFFFFFFFF ) + { + wxLogLastError("ModifyMenu"); + } + } +} - m_bChecked = bDoCheck; - } -} \ No newline at end of file