From: Vadim Zeitlin Date: Sat, 23 Jan 2010 13:21:46 +0000 (+0000) Subject: Correct alignment of menu accelerator strings in owner-drawn menus. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/9c32ed26a2b5aab5b8ea3c40af69e22ead895a32 Correct alignment of menu accelerator strings in owner-drawn menus. Draw them right-aligned as the native menus do. Closes #11479. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@63224 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/msw/menu.h b/include/wx/msw/menu.h index 0ce964a495..852bb646a6 100644 --- a/include/wx/msw/menu.h +++ b/include/wx/msw/menu.h @@ -91,6 +91,25 @@ public: wxAcceleratorTable *CreateAccelTable() const; #endif // wxUSE_ACCEL +#if wxUSE_OWNER_DRAWN + + int GetMaxAccelWidth() + { + if (m_maxAccelWidth == -1) + CalculateMaxAccelWidth(); + return m_maxAccelWidth; + } + + void ResetMaxAccelWidth() + { + m_maxAccelWidth = -1; + } + +private: + void CalculateMaxAccelWidth(); + +#endif // wxUSE_OWNER_DRAWN + protected: virtual wxMenuItem* DoAppend(wxMenuItem *item); virtual wxMenuItem* DoInsert(size_t pos, wxMenuItem *item); @@ -126,6 +145,9 @@ private: // the max width of menu items bitmaps int m_maxBitmapWidth; + + // the max width of menu items accels + int m_maxAccelWidth; #endif // wxUSE_OWNER_DRAWN DECLARE_DYNAMIC_CLASS_NO_COPY(wxMenu) diff --git a/include/wx/msw/menuitem.h b/include/wx/msw/menuitem.h index e885b98019..a4cbaa820d 100644 --- a/include/wx/msw/menuitem.h +++ b/include/wx/msw/menuitem.h @@ -107,6 +107,7 @@ public: const wxBitmap& GetDisabledBitmap() const { return m_bmpDisabled; } + int MeasureAccelWidth() const; // override wxOwnerDrawn base class virtuals virtual wxString GetName() const; diff --git a/src/msw/menu.cpp b/src/msw/menu.cpp index a64d5bcbb1..444a991ef8 100644 --- a/src/msw/menu.cpp +++ b/src/msw/menu.cpp @@ -271,6 +271,7 @@ void wxMenu::Init() #if wxUSE_OWNER_DRAWN m_ownerDrawn = false; m_maxBitmapWidth = 0; + m_maxAccelWidth = -1; #endif // wxUSE_OWNER_DRAWN // create the menu @@ -389,6 +390,8 @@ void wxMenu::UpdateAccel(wxMenuItem *item) { GetMenuBar()->RebuildAccelTable(); } + + ResetMaxAccelWidth(); } //else: it is a separator, they can't have accels, nothing to do } @@ -658,6 +661,8 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) // set menu as ownerdrawn m_ownerDrawn = true; + + ResetMaxAccelWidth(); } // only update our margin for equals alignment to other item else if ( !updateAllMargins ) @@ -802,6 +807,8 @@ wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) delete m_accels[n]; m_accels.RemoveAt(n); + + ResetMaxAccelWidth(); } //else: this item doesn't have an accel, nothing to do #endif // wxUSE_ACCEL @@ -852,6 +859,34 @@ wxAcceleratorTable *wxMenu::CreateAccelTable() const #endif // wxUSE_ACCEL +// --------------------------------------------------------------------------- +// ownerdrawn helpers +// --------------------------------------------------------------------------- + +#if wxUSE_OWNER_DRAWN + +void wxMenu::CalculateMaxAccelWidth() +{ + wxASSERT_MSG( m_maxAccelWidth == -1, wxT("it's really needed?") ); + + wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); + while (node) + { + wxMenuItem* item = node->GetData(); + + if ( item->IsOwnerDrawn() ) + { + int width = item->MeasureAccelWidth(); + if (width > m_maxAccelWidth ) + m_maxAccelWidth = width; + } + + node = node->GetNext(); + } +} + +#endif // wxUSE_OWNER_DRAWN + // --------------------------------------------------------------------------- // set wxMenu title // --------------------------------------------------------------------------- diff --git a/src/msw/menuitem.cpp b/src/msw/menuitem.cpp index 5214c1c813..83af40f8b3 100644 --- a/src/msw/menuitem.cpp +++ b/src/msw/menuitem.cpp @@ -211,16 +211,26 @@ public: Margins CheckMargin; // popup check margins Margins CheckBgMargin; // popup check background margins + Margins ArrowMargin; // popup submenu arrow margins + Margins SeparatorMargin; // popup separator margins SIZE CheckSize; // popup check size metric + SIZE ArrowSize; // popup submenu arrow size metric SIZE SeparatorSize; // popup separator size metric - int AccelBorder; // popup border space between - // item text and accelerator int TextBorder; // popup border space between // item text and gutter + int AccelBorder; // popup border space between + // item text and accelerator + + int ArrowBorder; // popup border space between + // item accelerator and submenu arrow + + int Offset; // system added space at the end of the menu, + // add this offset for remove the extra space + wxFont Font; // default menu font bool AlwaysShowCues; // must keyboard cues always be shown? @@ -309,6 +319,10 @@ void MenuDrawData::Init() TMT_CONTENTMARGINS, NULL, reinterpret_cast(&CheckBgMargin)); + theme->GetThemeMargins(hTheme, NULL, MENU_POPUPSUBMENU, 0, + TMT_CONTENTMARGINS, NULL, + reinterpret_cast(&ArrowMargin)); + theme->GetThemeMargins(hTheme, NULL, MENU_POPUPSEPARATOR, 0, TMT_SIZINGMARGINS, NULL, reinterpret_cast(&SeparatorMargin)); @@ -316,12 +330,19 @@ void MenuDrawData::Init() theme->GetThemePartSize(hTheme, NULL, MENU_POPUPCHECK, 0, NULL, TS_TRUE, &CheckSize); + theme->GetThemePartSize(hTheme, NULL, MENU_POPUPSUBMENU, 0, + NULL, TS_TRUE, &ArrowSize); + theme->GetThemePartSize(hTheme, NULL, MENU_POPUPSEPARATOR, 0, NULL, TS_TRUE, &SeparatorSize); - theme->GetThemeInt(hTheme, MENU_POPUPBORDERS, 0, TMT_BORDERSIZE, &AccelBorder); theme->GetThemeInt(hTheme, MENU_POPUPBACKGROUND, 0, TMT_BORDERSIZE, &TextBorder); + AccelBorder = 34; + ArrowBorder = 0; + + Offset = -14; + wxNativeFontInfo fontInfo; theme->GetThemeSysFont(hTheme, TMT_MENUFONT, &fontInfo.lf); Font = wxFont(fontInfo); @@ -352,6 +373,10 @@ void MenuDrawData::Init() CheckSize.cx = ::GetSystemMetrics(SM_CXMENUCHECK); CheckSize.cy = ::GetSystemMetrics(SM_CYMENUCHECK); + ArrowMargin = Margins(); + + ArrowSize = CheckSize; + // separator height with margins int sepFullSize = metrics.iMenuHeight / 2; @@ -365,6 +390,9 @@ void MenuDrawData::Init() TextBorder = 0; AccelBorder = 8; + ArrowBorder = 6; + + Offset = -12; Font = wxFont(wxNativeFontInfo(metrics.lfMenuFont)); @@ -683,6 +711,21 @@ void wxMenuItem::SetItemLabel(const wxString& txt) #if wxUSE_OWNER_DRAWN +int wxMenuItem::MeasureAccelWidth() const +{ + wxString accel = GetItemLabel().AfterFirst(wxT('\t')); + + wxMemoryDC dc; + wxFont font; + GetFontToUse(font); + dc.SetFont(font); + + wxCoord w; + dc.GetTextExtent(accel, &w, NULL); + + return w; +} + wxString wxMenuItem::GetName() const { return GetItemLabelText(); @@ -706,10 +749,7 @@ bool wxMenuItem::OnMeasureItem(size_t *width, size_t *height) return true; } - wxString str = GetItemLabel(); - - // text and accel separator char removal - str.Replace(wxT('\t'), wxEmptyString); + wxString str = GetName(); wxMemoryDC dc; wxFont font; @@ -719,12 +759,15 @@ bool wxMenuItem::OnMeasureItem(size_t *width, size_t *height) wxCoord w, h; dc.GetTextExtent(str, &w, &h); - *width = w + data->TextBorder + data->AccelBorder; + *width = data->TextBorder + w + data->AccelBorder; *height = h; - // system added space at the end of the menu for the submenu expansion - // arrow, but we must add a 4-pixel separator for better apperance - *width += 4; + w = m_parentMenu->GetMaxAccelWidth(); + if ( w > 0 ) + *width += w + data->ArrowBorder; + + *width += data->Offset; + *width += data->ArrowMargin.left + data->ArrowSize.cx + data->ArrowMargin.right; } else // don't draw the text, just the bitmap (if any) { @@ -941,10 +984,17 @@ bool wxMenuItem::OnDrawItem(wxDC& dc, const wxRect& rc, (stat & wxODDisabled) && !(stat & wxODSelected) ) flags |= DSS_DISABLED; - // right align accel string with right edge of menu - // (offset by the margin width) + int x = rcText.right - data->ArrowMargin.left + - data->ArrowSize.cx + - data->ArrowMargin.right + - data->ArrowBorder; + + // right align accel on FullTheme menu, left otherwise + if ( data->MenuLayout() == MenuDrawData::FullTheme) + x -= accelSize.cx; + else + x -= m_parentMenu->GetMaxAccelWidth(); - int x = rcText.right - 16 - accelSize.cx; int y = rcText.top + (rcText.bottom - rcText.top - accelSize.cy) / 2; ::DrawState(hdc, NULL, NULL, (LPARAM)accel.wx_str(),