int wxDirDialog::ShowModal() { WX_HOOK_MODAL_DIALOG(); wxWindow* const parent = GetParent(); WXHWND hWndParent = parent ? GetHwndOf(parent) : NULL; // Use IFileDialog under new enough Windows, it's more user-friendly. int rc; #if wxUSE_IFILEDIALOG if ( wxGetWinVersion() >= wxWinVersion_Vista ) { rc = ShowIFileDialog(hWndParent); } else { rc = wxID_NONE; } if ( rc == wxID_NONE ) #endif // wxUSE_IFILEDIALOG { rc = ShowSHBrowseForFolder(hWndParent); } // change current working directory if asked so if ( rc == wxID_OK && HasFlag(wxDD_CHANGE_DIR) ) wxSetWorkingDirectory(m_path); return rc; }
bool wxMenuItem::MSWMustUseOwnerDrawn() { // MIIM_BITMAP only works under WinME/2000+ so we always use owner // drawn item under the previous versions and we also have to use // them in any case if the item has custom colours or font static const wxWinVersion winver = wxGetWinVersion(); bool mustUseOwnerDrawn = winver < wxWinVersion_98 || GetTextColour().IsOk() || GetBackgroundColour().IsOk() || GetFont().IsOk(); // Windows XP or earlier don't display menu bitmaps bigger than // standard size correctly (they're truncated), so we must use // owner-drawn items to show them correctly there. OTOH Win7 // doesn't seem to have any problems with even very large bitmaps // so don't use owner-drawn items unnecessarily there (Vista wasn't // actually tested but I assume it works as 7 rather than as XP). if ( !mustUseOwnerDrawn && winver < wxWinVersion_Vista ) { const wxBitmap& bmpUnchecked = GetBitmap(false), bmpChecked = GetBitmap(true); if ( (bmpUnchecked.IsOk() && IsGreaterThanStdSize(bmpUnchecked)) || (bmpChecked.IsOk() && IsGreaterThanStdSize(bmpChecked)) ) { mustUseOwnerDrawn = true; } } return mustUseOwnerDrawn; }
// Returns non-NULL theme only if we're using Win7-style tooltips. static wxUxThemeEngine* GetTooltipTheme() { // Even themed applications under XP still use "classic" tooltips. if ( wxGetWinVersion() <= wxWinVersion_XP ) return NULL; return wxUxThemeEngine::GetIfActive(); }
void wxButton::DoSetAuthNeeded(bool show) { // show/hide UAC symbol on Windows Vista and later if ( wxGetWinVersion() >= wxWinVersion_6 ) { m_authNeeded = show; ::SendMessage(GetHwnd(), BCM_SETSHIELD, 0, show); InvalidateBestSize(); } }
wxSize wxHyperlinkCtrl::DoGetBestClientSize() const { // LM_GETIDEALSIZE only exists under Vista so use the generic version even // when using the native control under XP if ( !HasNativeHyperlinkCtrl() || (wxGetWinVersion() < wxWinVersion_6) ) return wxGenericHyperlinkCtrl::DoGetBestClientSize(); SIZE idealSize; ::SendMessage(m_hWnd, LM_GETIDEALSIZE, 0, (LPARAM)&idealSize); return wxSize(idealSize.cx, idealSize.cy); }
bool wxStaticBitmap::Create(wxWindow *parent, wxWindowID id, const wxGDIImage& bitmap, const wxPoint& pos, const wxSize& size, long style, const wxString& name) { if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) ) return false; // we may have either bitmap or icon: if a bitmap with mask is passed, we // will transform it to an icon ourselves because otherwise the mask will // be ignored by Windows m_isIcon = bitmap.IsKindOf(CLASSINFO(wxIcon)); wxGDIImage *image = ConvertImage( bitmap ); m_isIcon = image->IsKindOf( CLASSINFO(wxIcon) ); // create the native control if ( !MSWCreateControl(_T("STATIC"), wxEmptyString, pos, size) ) { // control creation failed return false; } // no need to delete the new image SetImageNoCopy(image); // GetBestSize will work properly now, so set the best size if needed SetInitialSize(size); // Win9x and 2000 don't draw correctly the images with alpha channel so we // need to draw them ourselves and it's easier to just always do it rather // than check if we have an image with alpha or not if ( wxGetWinVersion() <= wxWinVersion_2000 ) { Connect(wxEVT_PAINT, wxPaintEventHandler(wxStaticBitmap::DoPaintManually)); } return true; }
// returns the HBITMAP to use in MENUITEMINFO HBITMAP wxMenuItem::GetHBitmapForMenu(bool checked) { // Under versions of Windows older than Vista we can't pass HBITMAP // directly as hbmpItem for 2 reasons: // 1. We can't draw it with transparency then (this is not // very important now but would be with themed menu bg) // 2. Worse, Windows inverts the bitmap for the selected // item and this looks downright ugly // // So we prefer to instead draw it ourselves in MSWOnDrawItem().by using // HBMMENU_CALLBACK when inserting it // // However under Vista using HBMMENU_CALLBACK causes the entire menu to be // drawn using the classic theme instead of the current one and it does // handle transparency just fine so do use the real bitmap there #if wxUSE_IMAGE if ( wxGetWinVersion() >= wxWinVersion_Vista ) { wxBitmap bmp = GetBitmap(checked); if ( bmp.IsOk() ) { // we must use PARGB DIB for the menu bitmaps so ensure that we do wxImage img(bmp.ConvertToImage()); if ( !img.HasAlpha() ) { img.InitAlpha(); SetBitmap(img, checked); } return GetHbitmapOf(GetBitmap(checked)); } //else: bitmap is not set return NULL; } #endif // wxUSE_IMAGE return HBMMENU_CALLBACK; }
int wxDirDialog::ShowModal() { WX_HOOK_MODAL_DIALOG(); wxWindow* const parent = GetParent(); WXHWND hWndParent = parent ? GetHwndOf(parent) : NULL; // Use IFileDialog under new enough Windows, it's more user-friendly. int rc; #if wxUSE_IFILEDIALOG // While the new dialog is available under Vista, it may return a wrong // path there (see http://support.microsoft.com/kb/969885/en-us), so we // don't use it there by default. We could improve the version test to // allow its use if the comdlg32.dll version is greater than 6.0.6002.22125 // as this means that the hotfix correcting this bug is installed. if ( wxGetWinVersion() > wxWinVersion_Vista ) { rc = ShowIFileDialog(hWndParent); } else { rc = wxID_NONE; } if ( rc == wxID_NONE ) #endif // wxUSE_IFILEDIALOG { rc = ShowSHBrowseForFolder(hWndParent); } // change current working directory if asked so if ( rc == wxID_OK && HasFlag(wxDD_CHANGE_DIR) ) wxSetWorkingDirectory(m_path); return rc; }
void wxStaticBox::PaintForeground(wxDC& dc, const RECT& rc) { wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); MSWDefWindowProc(WM_PAINT, (WPARAM)GetHdcOf(*impl), 0); // when using XP themes, neither setting the text colour nor transparent // background mode doesn't change anything: the static box def window proc // still draws the label in its own colours, so we need to redraw the text // ourselves if we have a non default fg colour if ( m_hasFgCol && wxUxThemeEngine::GetIfActive() ) { // draw over the text in default colour in our colour HDC hdc = GetHdcOf(*impl); ::SetTextColor(hdc, GetForegroundColour().GetPixel()); const bool rtl = wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft; if ( rtl ) ::SetTextAlign(hdc, TA_RTLREADING | TA_RIGHT); // Get dimensions of the label const wxString label = GetLabel(); // choose the correct font AutoHFONT font; SelectInHDC selFont; if ( m_hasFont ) { selFont.Init(hdc, GetHfontOf(GetFont())); } else // no font set, use the one set by the theme { wxUxThemeHandle hTheme(this, L"BUTTON"); if ( hTheme ) { wxUxThemeFont themeFont; if ( wxUxThemeEngine::Get()->GetThemeFont ( hTheme, hdc, BP_GROUPBOX, GBS_NORMAL, TMT_FONT, themeFont.GetPtr() ) == S_OK ) { font.Init(themeFont.GetLOGFONT()); if ( font ) selFont.Init(hdc, font); } } } // Get the font extent int width, height; dc.GetTextExtent(wxStripMenuCodes(label, wxStrip_Mnemonics), &width, &height); int x; int y = height; // first we need to correctly paint the background of the label // as Windows ignores the brush offset when doing it // // FIXME: value of x is hardcoded as this is what it is on my system, // no idea if it's true everywhere RECT dimensions = {0, 0, 0, y}; if ( !rtl ) { x = 9; dimensions.left = x; dimensions.right = x + width; } else { x = rc.right - 7; dimensions.left = x - width; dimensions.right = x; } // need to adjust the rectangle to cover all the label background dimensions.left -= 2; dimensions.right += 2; dimensions.bottom += 2; if ( UseBgCol() ) { // our own background colour should be used for the background of // the label: this is consistent with the behaviour under pre-XP // systems (i.e. without visual themes) and generally makes sense wxBrush brush = wxBrush(GetBackgroundColour()); wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); ::FillRect(GetHdcOf(*impl), &dimensions, GetHbrushOf(brush)); } else // paint parent background { PaintBackground(dc, dimensions); } UINT drawTextFlags = DT_SINGLELINE | DT_VCENTER; // determine the state of UI queues to draw the text correctly under XP // and later systems static const bool isXPorLater = wxGetWinVersion() >= wxWinVersion_XP; if ( isXPorLater ) { if ( ::SendMessage(GetHwnd(), WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL ) { drawTextFlags |= DT_HIDEPREFIX; } } // now draw the text if ( !rtl ) { RECT rc2 = { x, 0, x + width, y }; ::DrawText(hdc, label.t_str(), label.length(), &rc2, drawTextFlags); } else // RTL { RECT rc2 = { x, 0, x - width, y }; ::DrawText(hdc, label.t_str(), label.length(), &rc2, drawTextFlags | DT_RTLREADING); } } }
WXLRESULT wxStaticBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { if ( nMsg == WM_NCHITTEST ) { // This code breaks some other processing such as enter/leave tracking // so it's off by default. static int s_useHTClient = -1; if (s_useHTClient == -1) s_useHTClient = wxSystemOptions::GetOptionInt(wxT("msw.staticbox.htclient")); if (s_useHTClient == 1) { int xPos = GET_X_LPARAM(lParam); int yPos = GET_Y_LPARAM(lParam); ScreenToClient(&xPos, &yPos); // Make sure you can drag by the top of the groupbox, but let // other (enclosed) controls get mouse events also if ( yPos < 10 ) return (long)HTCLIENT; } } if ( nMsg == WM_PRINTCLIENT ) { // we have to process WM_PRINTCLIENT ourselves as otherwise child // windows' background (eg buttons in radio box) would never be drawn // unless we have a parent with non default background // so check first if we have one if ( !HandlePrintClient((WXHDC)wParam) ) { // no, we don't, erase the background ourselves // (don't use our own) - see PaintBackground for explanation wxBrush brush(GetParent()->GetBackgroundColour()); wxFillRect(GetHwnd(), (HDC)wParam, GetHbrushOf(brush)); } return 0; } if ( nMsg == WM_UPDATEUISTATE ) { // DefWindowProc() redraws just the static box text when it gets this // message and it does it using the standard (blue in standard theme) // colour and not our own label colour that we use in PaintForeground() // resulting in the label mysteriously changing the colour when e.g. // "Alt" is pressed anywhere in the window, see #12497. // // To avoid this we simply refresh the window forcing our own code // redrawing the label in the correct colour to be called. This is // inefficient but there doesn't seem to be anything else we can do. // // Notice that the problem is XP-specific and doesn't arise under later // systems. if ( m_hasFgCol && wxGetWinVersion() == wxWinVersion_XP ) Refresh(); } return wxControl::MSWWindowProc(nMsg, wParam, lParam); }
void wxMenuItem::SetItemLabel(const wxString& txt) { wxString text = txt; // don't do anything if label didn't change if ( m_text == txt ) return; // wxMenuItemBase will do stock ID checks wxMenuItemBase::SetItemLabel(text); // the item can be not attached to any menu yet and SetItemLabel() is still // valid to call in this case and should do nothing else if ( !m_parentMenu ) return; #if wxUSE_ACCEL m_parentMenu->UpdateAccel(this); #endif // wxUSE_ACCEL const int itemPos = MSGetMenuItemPos(); if ( itemPos == -1 ) return; HMENU hMenu = GetHMenuOf(m_parentMenu); // update the text of the native menu item WinStruct<MENUITEMINFO> info; // surprisingly, calling SetMenuItemInfo() with just MIIM_STRING doesn't // work as it resets the menu bitmap, so we need to first get the old item // state and then modify it const bool isLaterThanWin95 = wxGetWinVersion() > wxWinVersion_95; info.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_DATA; if ( isLaterThanWin95 ) info.fMask |= MIIM_BITMAP | MIIM_FTYPE; else info.fMask |= MIIM_TYPE; if ( !::GetMenuItemInfo(hMenu, itemPos, TRUE, &info) ) { wxLogLastError(wxT("GetMenuItemInfo")); return; } #if wxUSE_OWNER_DRAWN // Don't set the text for the owner drawn items, they don't use it and even // though setting it doesn't seem to actually do any harm under Windows 7, // avoid doing this relatively nonsensical operation just in case it does // break something on other, past or future, Windows versions. // // Notice that we do need to call SetMenuItemInfo() even for the ownerdrawn // items however as otherwise their size wouldn't be recalculated as // WM_MEASUREITEM wouldn't be sent and this could result in display // problems if the length of the menu item changed significantly. // // Also notice that we shouldn't use our IsOwnerDrawn() because it can be // true because it was set by e.g. SetBitmap(), even if the item wasn't // made owner drawn at Windows level. if ( !(info.fState & MF_OWNERDRAW) ) #endif // wxUSE_OWNER_DRAWN { if ( isLaterThanWin95 ) info.fMask |= MIIM_STRING; //else: MIIM_TYPE already specified info.dwTypeData = wxMSW_CONV_LPTSTR(m_text); info.cch = m_text.length(); } if ( !::SetMenuItemInfo(hMenu, itemPos, TRUE, &info) ) { wxLogLastError(wxT("SetMenuItemInfo")); } }
// append a new item or submenu to the menu bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) { #if wxUSE_ACCEL UpdateAccel(pItem); #endif // wxUSE_ACCEL // we should support disabling the item even prior to adding it to the menu UINT flags = pItem->IsEnabled() ? MF_ENABLED : MF_GRAYED; // 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; } if ( pItem->IsSeparator() ) { flags |= MF_SEPARATOR; } // id is the numeric id for normal menu items and HMENU for submenus as // required by ::AppendMenu() API UINT_PTR id; wxMenu *submenu = pItem->GetSubMenu(); if ( submenu != NULL ) { wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") ); submenu->SetParent(this); id = (UINT_PTR)submenu->GetHMenu(); flags |= MF_POPUP; } else { id = pItem->GetMSWId(); } // prepare to insert the item in the menu wxString itemText = pItem->GetItemLabel(); LPCTSTR pData = NULL; if ( pos == (size_t)-1 ) { // append at the end (note that the item is already appended to // internal data structures) pos = GetMenuItemCount() - 1; } // Update radio groups data if we're inserting a new radio item. // // NB: If we supported inserting non-radio items in the middle of existing // radio groups to break them into two subgroups, we'd need to update // m_radioData in this case too but currently this is not supported. bool checkInitially = false; if ( pItem->GetKind() == wxITEM_RADIO ) { if ( !m_radioData ) m_radioData = new wxMenuRadioItemsData; if ( m_radioData->UpdateOnInsert(pos) ) checkInitially = true; } // adjust position to account for the title of a popup menu, if any if ( !GetMenuBar() && !m_title.empty() ) pos += 2; // for the title itself and its separator BOOL ok = false; #if wxUSE_OWNER_DRAWN // Under older systems mixing owner-drawn and non-owner-drawn items results // in inconsistent margins, so we force this one to be owner-drawn if any // other items already are. if ( m_ownerDrawn ) pItem->SetOwnerDrawn(true); #endif // wxUSE_OWNER_DRAWN // check if we have something more than a simple text item #if wxUSE_OWNER_DRAWN if ( pItem->IsOwnerDrawn() ) { #ifndef __DMC__ if ( !m_ownerDrawn && !pItem->IsSeparator() ) { // MIIM_BITMAP only works under WinME/2000+ so we always use owner // drawn item under the previous versions and we also have to use // them in any case if the item has custom colours or font static const wxWinVersion winver = wxGetWinVersion(); bool mustUseOwnerDrawn = winver < wxWinVersion_98 || pItem->GetTextColour().IsOk() || pItem->GetBackgroundColour().IsOk() || pItem->GetFont().IsOk(); if ( !mustUseOwnerDrawn ) { const wxBitmap& bmpUnchecked = pItem->GetBitmap(false), bmpChecked = pItem->GetBitmap(true); if ( (bmpUnchecked.IsOk() && IsGreaterThanStdSize(bmpUnchecked)) || (bmpChecked.IsOk() && IsGreaterThanStdSize(bmpChecked)) ) { mustUseOwnerDrawn = true; } } // use InsertMenuItem() if possible as it's guaranteed to look // correct while our owner-drawn code is not if ( !mustUseOwnerDrawn ) { WinStruct<MENUITEMINFO> mii; mii.fMask = MIIM_STRING | MIIM_DATA; // don't set hbmpItem for the checkable items as it would // be used for both checked and unchecked state if ( pItem->IsCheckable() ) { mii.fMask |= MIIM_CHECKMARKS; mii.hbmpChecked = GetHBitmapForMenu(pItem, true); mii.hbmpUnchecked = GetHBitmapForMenu(pItem, false); } else if ( pItem->GetBitmap().IsOk() ) { mii.fMask |= MIIM_BITMAP; mii.hbmpItem = GetHBitmapForMenu(pItem); } mii.cch = itemText.length(); mii.dwTypeData = const_cast<wxChar *>(itemText.wx_str()); if ( flags & MF_POPUP ) { mii.fMask |= MIIM_SUBMENU; mii.hSubMenu = GetHmenuOf(pItem->GetSubMenu()); } else { mii.fMask |= MIIM_ID; mii.wID = id; } mii.dwItemData = reinterpret_cast<ULONG_PTR>(pItem); ok = ::InsertMenuItem(GetHmenu(), pos, TRUE /* by pos */, &mii); if ( !ok ) { wxLogLastError(wxT("InsertMenuItem()")); } else // InsertMenuItem() ok { // we need to remove the extra indent which is reserved for // the checkboxes by default as it looks ugly unless check // boxes are used together with bitmaps and this is not the // case in wx API WinStruct<MENUINFO> mi; // don't call SetMenuInfo() directly, this would prevent // the app from starting up under Windows 95/NT 4 typedef BOOL (WINAPI *SetMenuInfo_t)(HMENU, MENUINFO *); wxDynamicLibrary dllUser(wxT("user32")); wxDYNLIB_FUNCTION(SetMenuInfo_t, SetMenuInfo, dllUser); if ( pfnSetMenuInfo ) { mi.fMask = MIM_STYLE; mi.dwStyle = MNS_CHECKORBMP; if ( !(*pfnSetMenuInfo)(GetHmenu(), &mi) ) { wxLogLastError(wxT("SetMenuInfo(MNS_NOCHECK)")); } } // tell the item that it's not really owner-drawn but only // needs to draw its bitmap, the rest is done by Windows pItem->SetOwnerDrawn(false); } } } #endif // __DMC__ if ( !ok ) { // item draws itself, pass pointer to it in data parameter flags |= MF_OWNERDRAW; pData = (LPCTSTR)pItem; bool updateAllMargins = false; // get size of bitmap always return valid value (0 for invalid bitmap), // so we don't needed check if bitmap is valid ;) int uncheckedW = pItem->GetBitmap(false).GetWidth(); int checkedW = pItem->GetBitmap(true).GetWidth(); if ( m_maxBitmapWidth < uncheckedW ) { m_maxBitmapWidth = uncheckedW; updateAllMargins = true; } if ( m_maxBitmapWidth < checkedW ) { m_maxBitmapWidth = checkedW; updateAllMargins = true; } // make other item ownerdrawn and update margin width for equals alignment if ( !m_ownerDrawn || updateAllMargins ) { // we must use position in SetOwnerDrawnMenuItem because // all separators have the same id int pos = 0; wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); while (node) { wxMenuItem* item = node->GetData(); if ( !item->IsOwnerDrawn()) { item->SetOwnerDrawn(true); SetOwnerDrawnMenuItem(GetHmenu(), pos, reinterpret_cast<ULONG_PTR>(item), TRUE); } item->SetMarginWidth(m_maxBitmapWidth); node = node->GetNext(); pos++; } // set menu as ownerdrawn m_ownerDrawn = true; ResetMaxAccelWidth(); } // only update our margin for equals alignment to other item else if ( !updateAllMargins ) { pItem->SetMarginWidth(m_maxBitmapWidth); } } } else #endif // wxUSE_OWNER_DRAWN { // item is just a normal string (passed in data parameter) flags |= MF_STRING; #ifdef __WXWINCE__ itemText = wxMenuItem::GetLabelText(itemText); #endif pData = (wxChar*)itemText.wx_str(); } // item might have already been inserted by InsertMenuItem() above if ( !ok ) { if ( !::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData) ) { wxLogLastError(wxT("InsertMenu[Item]()")); return false; } } // Check the item if it should be initially checked. if ( checkInitially ) pItem->Check(true); // if we just appended the title, highlight it if ( id == (UINT_PTR)idMenuTitle ) { // visually select the menu title SetDefaultMenuItem(GetHmenu(), id); } // if we're already attached to the menubar, we must update it if ( IsAttached() && GetMenuBar()->IsAttached() ) { GetMenuBar()->Refresh(); } return true; }
WXLRESULT wxFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) { WXLRESULT rc = 0; bool processed = false; switch ( message ) { case WM_CLOSE: // if we can't close, tell the system that we processed the // message - otherwise it would close us processed = !Close(); break; case WM_SIZE: processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam); break; case WM_COMMAND: { WORD id, cmd; WXHWND hwnd; UnpackCommand((WXWPARAM)wParam, (WXLPARAM)lParam, &id, &hwnd, &cmd); HandleCommand(id, cmd, (WXHWND)hwnd); // don't pass WM_COMMAND to the base class whether we processed // it or not because we did generate an event for it (our // HandleCommand() calls the base class version) and we must // not do it again or the handlers which skip the event would // be called twice processed = true; } break; #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) #if wxUSE_MENUS case WM_INITMENUPOPUP: processed = HandleMenuPopup(wxEVT_MENU_OPEN, (WXHMENU)wParam); break; case WM_MENUSELECT: { WXWORD item, flags; WXHMENU hmenu; UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu); processed = HandleMenuSelect(item, flags, hmenu); } break; case WM_EXITMENULOOP: // Under Windows 98 and 2000 and later we're going to get // WM_UNINITMENUPOPUP which will be used to generate this event // with more information (notably the menu that was closed) so we // only need this one under old Windows systems where the newer // event is never sent. if ( wxGetWinVersion() < wxWinVersion_98 ) processed = HandleExitMenuLoop(wParam); break; case WM_UNINITMENUPOPUP: processed = HandleMenuPopup(wxEVT_MENU_CLOSE, (WXHMENU)wParam); break; #endif // wxUSE_MENUS case WM_QUERYDRAGICON: { const wxIcon& icon = GetIcon(); HICON hIcon = icon.IsOk() ? GetHiconOf(icon) : (HICON)GetDefaultIcon(); rc = (WXLRESULT)hIcon; processed = rc != 0; } break; #endif // !__WXMICROWIN__ } if ( !processed ) rc = wxFrameBase::MSWWindowProc(message, wParam, lParam); return rc; }
void wxAuiMSWTabArt::DrawTab(wxDC& dc, wxWindow* wnd, const wxAuiNotebookPage& page, const wxRect& in_rect, int close_button_state, wxRect* out_tab_rect, wxRect* out_button_rect, int* x_extent) { if ( !IsThemed() ) { wxAuiGenericTabArt::DrawTab(dc, wnd, page, in_rect, close_button_state, out_tab_rect, out_button_rect, x_extent); return; } if ( !m_closeBtnSize.IsFullySpecified() ) InitSizes(wnd, dc); // figure out the size of the tab wxSize tabSize = GetTabSize(dc, wnd, page.caption, page.bitmap, page.active, close_button_state, x_extent); wxCoord tabHeight = tabSize.y; wxCoord tabWidth = tabSize.x; wxCoord tabX = in_rect.x; wxCoord tabY = 0; if (!page.active) { tabY += wnd->FromDIP(2); tabHeight -= wnd->FromDIP(2); } else { tabX -= wnd->FromDIP(2); tabWidth += wnd->FromDIP(4); tabHeight += 2; } int clipWidth = tabWidth; if ( tabX + clipWidth > in_rect.x + in_rect.width ) clipWidth = (in_rect.x + in_rect.width) - tabX; dc.SetClippingRegion(tabX - wnd->FromDIP(2), tabY, clipWidth + wnd->FromDIP(4), tabHeight); // draw tab wxRect tabRect(tabX, tabY, tabWidth, tabHeight); int tabState; if ( page.active ) tabState = TIS_SELECTED; else if ( page.hover ) tabState = TIS_HOT; else tabState = TIS_NORMAL; wxUxThemeHandle hTabTheme(wnd, L"Tab"); RECT tabR; wxCopyRectToRECT(tabRect, tabR); ::DrawThemeBackground(hTabTheme, GetHdcOf(dc.GetTempHDC()), TABP_TABITEM, tabState, &tabR, NULL); // Apparently, in at least some Windows 10 installations the call above // does not draw the left edge of the first tab and it needs to be drawn // separately, or it wouldn't be drawn at all. if ( tabX == GetIndentSize() ) { ::DrawThemeBackground ( hTabTheme, GetHdcOf(dc.GetTempHDC()), TABP_TABITEMLEFTEDGE, tabState, &tabR, NULL ); } wxRect textRect = tabRect; if ( !page.active ) textRect.Offset(0, wnd->FromDIP(1)); if ( close_button_state != wxAUI_BUTTON_STATE_HIDDEN ) textRect.width -= m_closeBtnSize.x + wnd->FromDIP(3); dc.SetFont(wnd->GetFont()); dc.DrawLabel(page.caption, page.bitmap, textRect, wxALIGN_CENTRE); // draw focus rectangle if ( page.active && (wnd->FindFocus() == wnd) ) { wxRect focusRect = tabRect; focusRect.Deflate(wnd->FromDIP(2)); wxRendererNative::Get().DrawFocusRect(wnd, dc, focusRect, 0); } // draw close button if ( close_button_state != wxAUI_BUTTON_STATE_HIDDEN ) { wxUxThemeHandle hToolTipTheme(wnd, L"TOOLTIP"); int btnState; if ( close_button_state == wxAUI_BUTTON_STATE_HOVER ) btnState = TTCS_HOT; else if ( close_button_state == wxAUI_BUTTON_STATE_PRESSED ) btnState = TTCS_PRESSED; else btnState = TTCS_NORMAL; int offsetY = tabY; if ( wxGetWinVersion() < wxWinVersion_Vista ) offsetY++; // WinXP theme needs a little more padding wxRect rect(tabX + tabWidth - m_closeBtnSize.x - wnd->FromDIP(4), offsetY + (tabHeight / 2) - (m_closeBtnSize.y / 2), m_closeBtnSize.x, m_closeBtnSize.y); RECT btnR; wxCopyRectToRECT(rect, btnR); ::DrawThemeBackground(hToolTipTheme, GetHdcOf(dc.GetTempHDC()), TTP_CLOSE, btnState, &btnR, NULL); if ( out_button_rect ) *out_button_rect = rect; } *out_tab_rect = wxRect(tabX, tabY, tabWidth, tabHeight); dc.DestroyClippingRegion(); }
void wxMenuItem::SetItemLabel(const wxString& txt) { wxString text = txt; // don't do anything if label didn't change if ( m_text == txt ) return; // wxMenuItemBase will do stock ID checks wxMenuItemBase::SetItemLabel(text); // the item can be not attached to any menu yet and SetItemLabel() is still // valid to call in this case and should do nothing else if ( !m_parentMenu ) return; #if wxUSE_ACCEL m_parentMenu->UpdateAccel(this); #endif // wxUSE_ACCEL const UINT id = GetMSWId(); HMENU hMenu = GetHMenuOf(m_parentMenu); if ( !hMenu || ::GetMenuState(hMenu, id, MF_BYCOMMAND) == (UINT)-1 ) return; #if wxUSE_OWNER_DRAWN if ( IsOwnerDrawn() ) { // we don't need to do anything for owner drawn items, they will redraw // themselves using the new text the next time they're displayed return; } #endif // owner drawn // update the text of the native menu item WinStruct<MENUITEMINFO> info; // surprisingly, calling SetMenuItemInfo() with just MIIM_STRING doesn't // work as it resets the menu bitmap, so we need to first get the old item // state and then modify it const bool isLaterThanWin95 = wxGetWinVersion() > wxWinVersion_95; info.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_DATA; if ( isLaterThanWin95 ) info.fMask |= MIIM_BITMAP | MIIM_FTYPE; else info.fMask |= MIIM_TYPE; if ( !::GetMenuItemInfo(hMenu, id, FALSE, &info) ) { wxLogLastError(wxT("GetMenuItemInfo")); return; } if ( isLaterThanWin95 ) info.fMask |= MIIM_STRING; //else: MIIM_TYPE already specified info.dwTypeData = (LPTSTR)m_text.wx_str(); info.cch = m_text.length(); if ( !::SetMenuItemInfo(hMenu, id, FALSE, &info) ) { wxLogLastError(wxT("SetMenuItemInfo")); } }
bool wxMSWOwnerDrawnButtonBase::MSWDrawButton(WXDRAWITEMSTRUCT *item) { DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)item; if ( !MSWIsOwnerDrawn() || dis->CtlType != ODT_BUTTON ) return false; // shall we draw a focus rect? const bool isFocused = m_isPressed || m_win->HasFocus(); int flags = MSWGetButtonCheckedFlag(); if ( dis->itemState & ODS_SELECTED ) flags |= wxCONTROL_SELECTED | wxCONTROL_PRESSED; if ( !m_win->IsEnabled() ) flags |= wxCONTROL_DISABLED; if ( m_isPressed ) flags |= wxCONTROL_PRESSED; if ( wxFindWindowAtPoint(wxGetMousePosition()) == m_win ) flags |= wxCONTROL_CURRENT; // calculate the rectangles for the button itself and the label HDC hdc = dis->hDC; const RECT& rect = dis->rcItem; // calculate the rectangles for the button itself and the label const wxSize bestSize = m_win->GetBestSize(); RECT rectButton, rectLabel; rectLabel.top = rect.top + (rect.bottom - rect.top - bestSize.y) / 2; rectLabel.bottom = rectLabel.top + bestSize.y; // choose the values consistent with those used for native, non // owner-drawn, buttons static const int MARGIN = 3; int CXMENUCHECK = ::GetSystemMetrics(SM_CXMENUCHECK) + 1; // the buttons were even bigger under Windows XP if ( wxGetWinVersion() < wxWinVersion_6 ) CXMENUCHECK += 2; // The space between the button and the label // is included in the button bitmap. const int buttonSize = wxMin(CXMENUCHECK - MARGIN, m_win->GetSize().y); rectButton.top = rect.top + (rect.bottom - rect.top - buttonSize) / 2; rectButton.bottom = rectButton.top + buttonSize; const bool isRightAligned = m_win->HasFlag(wxALIGN_RIGHT); if ( isRightAligned ) { rectLabel.right = rect.right - CXMENUCHECK; rectLabel.left = rect.left; rectButton.left = rectLabel.right + ( CXMENUCHECK + MARGIN - buttonSize ) / 2; rectButton.right = rectButton.left + buttonSize; } else // normal, left-aligned button { rectButton.left = rect.left + ( CXMENUCHECK - MARGIN - buttonSize ) / 2; rectButton.right = rectButton.left + buttonSize; rectLabel.left = rect.left + CXMENUCHECK; rectLabel.right = rect.right; } // Erase the background. ::FillRect(hdc, &rect, m_win->MSWGetBgBrush(hdc)); // draw the button itself wxDCTemp dc(hdc); MSWDrawButtonBitmap(dc, wxRectFromRECT(rectButton), flags); // draw the text const wxString& label = m_win->GetLabel(); // first we need to measure it UINT fmt = DT_NOCLIP; // drawing underlying doesn't look well with focus rect (and the native // control doesn't do it) if ( isFocused ) fmt |= DT_HIDEPREFIX; if ( isRightAligned ) fmt |= DT_RIGHT; // TODO: also use DT_HIDEPREFIX if the system is configured so // we need to get the label real size first if we have to draw a focus rect // around it if ( isFocused ) { RECT oldLabelRect = rectLabel; // needed if right aligned if ( !::DrawText(hdc, label.t_str(), label.length(), &rectLabel, fmt | DT_CALCRECT) ) { wxLogLastError(wxT("DrawText(DT_CALCRECT)")); } if ( isRightAligned ) { // move the label rect to the right const int labelWidth = rectLabel.right - rectLabel.left; rectLabel.right = oldLabelRect.right; rectLabel.left = rectLabel.right - labelWidth; } } if ( flags & wxCONTROL_DISABLED ) { ::SetTextColor(hdc, ::GetSysColor(COLOR_GRAYTEXT)); } if ( !::DrawText(hdc, label.t_str(), label.length(), &rectLabel, fmt) ) { wxLogLastError(wxT("DrawText()")); } // finally draw the focus if ( isFocused ) { rectLabel.left--; rectLabel.right++; if ( !::DrawFocusRect(hdc, &rectLabel) ) { wxLogLastError(wxT("DrawFocusRect()")); } } return true; }
// append a new item or submenu to the menu bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) { #if wxUSE_ACCEL UpdateAccel(pItem); #endif // wxUSE_ACCEL 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; } if ( pItem->IsSeparator() ) { flags |= MF_SEPARATOR; } // 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_MSG( submenu->GetHMenu(), wxT("invalid submenu") ); submenu->SetParent(this); id = (UINT)submenu->GetHMenu(); flags |= MF_POPUP; } else { id = pItem->GetId(); } // prepare to insert the item in the menu wxString itemText = pItem->GetText(); LPCTSTR pData = NULL; if ( pos == (size_t)-1 ) { // append at the end (note that the item is already appended to // internal data structures) pos = GetMenuItemCount() - 1; } // adjust position to account for the title, if any if ( !m_title.empty() ) pos += 2; // for the title itself and its separator BOOL ok = false; // check if we have something more than a simple text item #if wxUSE_OWNER_DRAWN if ( pItem->IsOwnerDrawn() ) { // is the item owner-drawn just because of the bitmap? if ( pItem->GetBitmap().Ok() && !pItem->GetTextColour().Ok() && !pItem->GetBackgroundColour().Ok() && !pItem->GetFont().Ok() ) { // try to use InsertMenuItem() as it's guaranteed to look correctly // while our owner-drawning code is not // first compile-time check #ifdef MIIM_BITMAP WinStruct<MENUITEMINFO> mii; // now run-time one: MIIM_BITMAP only works under WinME/2000+ if ( wxGetWinVersion() >= wxWinVersion_98 ) { mii.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_BITMAP; mii.wID = id; mii.cch = itemText.length(); mii.dwTypeData = wx_const_cast(wxChar *, itemText.c_str()); // we can't pass HBITMAP directly as hbmpItem for 2 reasons: // 1. we can't draw it with transparency then (this is not // very important now but would be with themed menu bg) // 2. worse, Windows inverses the bitmap for the selected // item and this looks downright ugly // // so instead draw it ourselves in MSWOnDrawItem() mii.dwItemData = wx_reinterpret_cast(ULONG_PTR, pItem); mii.hbmpItem = HBMMENU_CALLBACK; ok = ::InsertMenuItem(GetHmenu(), pos, TRUE /* by pos */, &mii); if ( !ok ) { wxLogLastError(wxT("InsertMenuItem()")); } else // InsertMenuItem() ok { // we need to remove the extra indent which is reserved for // the checkboxes by default as it looks ugly unless check // boxes are used together with bitmaps and this is not the // case in wx API WinStruct<MENUINFO> mi; // don't call SetMenuInfo() directly, this would prevent // the app from starting up under Windows 95/NT 4 typedef BOOL (WINAPI *SetMenuInfo_t)(HMENU, MENUINFO *); wxDynamicLibrary dllUser(_T("user32")); wxDYNLIB_FUNCTION(SetMenuInfo_t, SetMenuInfo, dllUser); if ( pfnSetMenuInfo ) { mi.fMask = MIM_STYLE; mi.dwStyle = MNS_CHECKORBMP; if ( !(*pfnSetMenuInfo)(GetHmenu(), &mi) ) wxLogLastError(_T("SetMenuInfo(MNS_NOCHECK)")); } // tell the item that it's not really owner-drawn but only // needs to draw its bitmap, the rest is done by Windows pItem->ResetOwnerDrawn(); } } #endif // MIIM_BITMAP }
// append a new item or submenu to the menu bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) { #if wxUSE_ACCEL UpdateAccel(pItem); #endif // wxUSE_ACCEL // we should support disabling the item even prior to adding it to the menu UINT flags = pItem->IsEnabled() ? MF_ENABLED : MF_GRAYED; // 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; } if ( pItem->IsSeparator() ) { flags |= MF_SEPARATOR; } // id is the numeric id for normal menu items and HMENU for submenus as // required by ::AppendMenu() API UINT_PTR id; wxMenu *submenu = pItem->GetSubMenu(); if ( submenu != NULL ) { wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") ); submenu->SetParent(this); id = (UINT_PTR)submenu->GetHMenu(); flags |= MF_POPUP; } else { id = pItem->GetMSWId(); } // prepare to insert the item in the menu wxString itemText = pItem->GetItemLabel(); LPCTSTR pData = NULL; if ( pos == (size_t)-1 ) { // append at the end (note that the item is already appended to // internal data structures) pos = GetMenuItemCount() - 1; } // adjust position to account for the title, if any if ( !m_title.empty() ) pos += 2; // for the title itself and its separator BOOL ok = false; #if wxUSE_OWNER_DRAWN // Under older systems mixing owner-drawn and non-owner-drawn items results // in inconsistent margins, so we force this one to be owner-drawn if any // other items already are. Later we might want to use a boolean in the // wxMenu to avoid search. Also we might make this fix unnecessary by // getting the correct margin using NONCLIENTMETRICS. static const wxWinVersion winver = wxGetWinVersion(); if ( winver < wxWinVersion_XP && !pItem->IsOwnerDrawn() && !pItem->IsSeparator() ) { // Check if any other items are ownerdrawn, and make ownerdrawn if so wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); while (node) { if (node->GetData()->IsOwnerDrawn()) { pItem->SetOwnerDrawn(true); break; } node = node->GetNext(); } } #endif // wxUSE_OWNER_DRAWN // check if we have something more than a simple text item #if wxUSE_OWNER_DRAWN if ( pItem->IsOwnerDrawn() ) { #ifndef __DMC__ // MIIM_BITMAP only works under WinME/2000+ so we always use owner // drawn item under the previous versions and we also have to use them // in any case if the item has custom colours or font bool mustUseOwnerDrawn = winver < wxWinVersion_98 || pItem->GetTextColour().Ok() || pItem->GetBackgroundColour().Ok() || pItem->GetFont().Ok(); if ( !mustUseOwnerDrawn ) { const wxBitmap& bmpUnchecked = pItem->GetBitmap(false), bmpChecked = pItem->GetBitmap(true); if ( (bmpUnchecked.Ok() && !IsLessThanStdSize(bmpUnchecked)) || (bmpChecked.Ok() && !IsLessThanStdSize(bmpChecked)) ) { mustUseOwnerDrawn = true; } } // use InsertMenuItem() if possible as it's guaranteed to look correct // while our owner-drawn code is not if ( !mustUseOwnerDrawn ) { WinStruct<MENUITEMINFO> mii; mii.fMask = MIIM_STRING | MIIM_DATA; if ( pItem->GetBitmap().IsOk() ) { mii.fMask |= MIIM_BITMAP; mii.hbmpItem = GetHBitmapForMenu(pItem); } if ( pItem->IsCheckable() ) { mii.fMask |= MIIM_CHECKMARKS; mii.hbmpChecked = GetHBitmapForMenu(pItem, true); mii.hbmpUnchecked = GetHBitmapForMenu(pItem, false); } mii.cch = itemText.length(); mii.dwTypeData = const_cast<wxChar *>(itemText.wx_str()); if ( flags & MF_POPUP ) { mii.fMask |= MIIM_SUBMENU; mii.hSubMenu = GetHmenuOf(pItem->GetSubMenu()); } else { mii.fMask |= MIIM_ID; mii.wID = id; } mii.dwItemData = reinterpret_cast<ULONG_PTR>(pItem); ok = ::InsertMenuItem(GetHmenu(), pos, TRUE /* by pos */, &mii); if ( !ok ) { wxLogLastError(wxT("InsertMenuItem()")); } else // InsertMenuItem() ok { // we need to remove the extra indent which is reserved for // the checkboxes by default as it looks ugly unless check // boxes are used together with bitmaps and this is not the // case in wx API WinStruct<MENUINFO> mi; // don't call SetMenuInfo() directly, this would prevent // the app from starting up under Windows 95/NT 4 typedef BOOL (WINAPI *SetMenuInfo_t)(HMENU, MENUINFO *); wxDynamicLibrary dllUser(wxT("user32")); wxDYNLIB_FUNCTION(SetMenuInfo_t, SetMenuInfo, dllUser); if ( pfnSetMenuInfo ) { mi.fMask = MIM_STYLE; mi.dwStyle = MNS_CHECKORBMP; if ( !(*pfnSetMenuInfo)(GetHmenu(), &mi) ) { wxLogLastError(wxT("SetMenuInfo(MNS_NOCHECK)")); } } // tell the item that it's not really owner-drawn but only // needs to draw its bitmap, the rest is done by Windows pItem->ResetOwnerDrawn(); } } #endif // __DMC__ if ( !ok ) { // item draws itself, pass pointer to it in data parameter flags |= MF_OWNERDRAW; pData = (LPCTSTR)pItem; } } else #endif // wxUSE_OWNER_DRAWN { // item is just a normal string (passed in data parameter) flags |= MF_STRING; #ifdef __WXWINCE__ itemText = wxMenuItem::GetLabelText(itemText); #endif pData = (wxChar*)itemText.wx_str(); } // item might have already been inserted by InsertMenuItem() above if ( !ok ) { if ( !::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData) ) { wxLogLastError(wxT("InsertMenu[Item]()")); return false; } } // if we just appended the title, highlight it if ( id == idMenuTitle ) { // visually select the menu title SetDefaultMenuItem(GetHmenu(), id); } // if we're already attached to the menubar, we must update it if ( IsAttached() && GetMenuBar()->IsAttached() ) { GetMenuBar()->Refresh(); } return true; }