void wxChoice::SetString(unsigned int n, const wxString& s) { wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::SetString") ); // we have to delete and add back the string as there is no way to change a // string in place // we need to preserve the client data manually void *oldData = NULL; wxClientData *oldObjData = NULL; if ( HasClientUntypedData() ) oldData = GetClientData(n); else if ( HasClientObjectData() ) oldObjData = GetClientObject(n); // and also the selection if we're going to delete the item that was // selected const bool wasSelected = static_cast<int>(n) == GetSelection(); ::SendMessage(GetHwnd(), CB_DELETESTRING, n, 0); ::SendMessage(GetHwnd(), CB_INSERTSTRING, n, wxMSW_CONV_LPARAM(s) ); // restore the client data if ( oldData ) SetClientData(n, oldData); else if ( oldObjData ) SetClientObject(n, oldObjData); // and the selection if ( wasSelected ) SetSelection(n); // the width could have changed so the best size needs to be recomputed InvalidateBestSize(); }
int wxDirDialog::ShowSHBrowseForFolder(WXHWND owner) { BROWSEINFO bi; bi.hwndOwner = owner; bi.pidlRoot = NULL; bi.pszDisplayName = NULL; bi.lpszTitle = m_message.c_str(); bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT; bi.lpfn = BrowseCallbackProc; bi.lParam = wxMSW_CONV_LPARAM(m_path); // param for the callback static const int verComCtl32 = wxApp::GetComCtl32Version(); // we always add the edit box (it doesn't hurt anybody, does it?) bi.ulFlags |= BIF_EDITBOX; // to have the "New Folder" button we must use the "new" dialog style which // is also the only way to have a resizable dialog // const bool needNewDir = !HasFlag(wxDD_DIR_MUST_EXIST); if ( needNewDir || HasFlag(wxRESIZE_BORDER) ) { if (needNewDir) { bi.ulFlags |= BIF_NEWDIALOGSTYLE; } else { // Versions < 600 doesn't support BIF_NONEWFOLDERBUTTON // The only way to get rid of the Make New Folder button is use // the old dialog style which doesn't have the button thus we // simply don't set the New Dialog Style for such comctl versions. if (verComCtl32 >= 600) { bi.ulFlags |= BIF_NEWDIALOGSTYLE; bi.ulFlags |= BIF_NONEWFOLDERBUTTON; } } } // do show the dialog wxItemIdList pidl(SHBrowseForFolder(&bi)); wxItemIdList::Free((LPITEMIDLIST)bi.pidlRoot); if ( !pidl ) { // Cancel button pressed return wxID_CANCEL; } m_path = pidl.GetPath(); return m_path.empty() ? wxID_CANCEL : wxID_OK; }
static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) { switch(uMsg) { #ifdef BFFM_SETSELECTION case BFFM_INITIALIZED: // sent immediately after initialisation and so we may set the // initial selection here // // wParam = TRUE => lParam is a string and not a PIDL ::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData); break; #endif // BFFM_SETSELECTION case BFFM_SELCHANGED: // note that this doesn't work with the new style UI (MSDN doesn't // say anything about it, but the comments in shlobj.h do!) but we // still execute this code in case it starts working again with the // "new new UI" (or would it be "NewUIEx" according to tradition?) { // Set the status window to the currently selected path. wxString strDir; if ( SHGetPathFromIDList((LPITEMIDLIST)lp, wxStringBuffer(strDir, MAX_PATH)) ) { // NB: this shouldn't be necessary with the new style box // (which is resizable), but as for now it doesn't work // anyhow (see the comment above) no harm in doing it // need to truncate or it displays incorrectly static const size_t maxChars = 37; if ( strDir.length() > maxChars ) { strDir = strDir.Right(maxChars); strDir = wxString(wxT("...")) + strDir; } SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, wxMSW_CONV_LPARAM(strDir)); } } break; //case BFFM_VALIDATEFAILED: -- might be used to provide custom message // if the user types in invalid dir name } return 0; }
int wxControlWithItems::MSWInsertOrAppendItem(unsigned pos, const wxString& item, unsigned wm) { LRESULT n = SendMessage((HWND)MSWGetItemsHWND(), wm, pos, wxMSW_CONV_LPARAM(item)); if ( n == CB_ERR || n == CB_ERRSPACE ) { wxLogLastError(wxT("SendMessage(XX_ADD/INSERTSTRING)")); return wxNOT_FOUND; } return n; }
void wxCommandLinkButton::SetMainLabelAndNote(const wxString& mainLabel, const wxString& note) { if ( HasNativeCommandLinkButton() ) { wxButton::SetLabel(mainLabel); ::SendMessage(m_hWnd, BCM_SETNOTE, 0, wxMSW_CONV_LPARAM(note)); // Preserve the user-specified label for GetLabel() m_labelOrig = mainLabel; if ( !note.empty() ) m_labelOrig << '\n' << note; } else { wxGenericCommandLinkButton::SetMainLabelAndNote(mainLabel, note); } }
int wxChoice::FindString(const wxString& s, bool bCase) const { #if defined(__WATCOMC__) && defined(__WIN386__) // For some reason, Watcom in WIN386 mode crashes in the CB_FINDSTRINGEXACT message. // wxChoice::Do it the long way instead. unsigned int count = GetCount(); for ( unsigned int i = 0; i < count; i++ ) { // as CB_FINDSTRINGEXACT is case insensitive, be case insensitive too if (GetString(i).IsSameAs(s, bCase)) return i; } return wxNOT_FOUND; #else // !Watcom //TODO: Evidently some MSW versions (all?) don't like empty strings //passed to SendMessage, so we have to do it ourselves in that case if ( s.empty() ) { unsigned int count = GetCount(); for ( unsigned int i = 0; i < count; i++ ) { if (GetString(i).empty()) return i; } return wxNOT_FOUND; } else if (bCase) { // back to base class search for not native search type return wxItemContainerImmutable::FindString( s, bCase ); } else { int pos = (int)SendMessage(GetHwnd(), CB_FINDSTRINGEXACT, (WPARAM)-1, wxMSW_CONV_LPARAM(s)); return pos == LB_ERR ? wxNOT_FOUND : pos; } #endif // Watcom/!Watcom }
// draw the item bool wxOwnerDrawn::OnDrawItem(wxDC& dc, const wxRect& rc, wxODAction, wxODStatus stat) { // we do nothing if item isn't ownerdrawn if ( !IsOwnerDrawn() ) return true; wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); HDC hdc = GetHdcOf(*impl); RECT rect; wxCopyRectToRECT(rc, rect); { // set the font and colors wxFont font; GetFontToUse(font); wxColour colText, colBack; GetColourToUse(stat, colText, colBack); SelectInHDC selFont(hdc, GetHfontOf(font)); wxMSWImpl::wxTextColoursChanger textCol(hdc, colText, colBack); wxMSWImpl::wxBkModeChanger bkMode(hdc, wxBRUSHSTYLE_TRANSPARENT); AutoHBRUSH hbr(wxColourToPalRGB(colBack)); SelectInHDC selBrush(hdc, hbr); ::FillRect(hdc, &rect, hbr); // using native API because it recognizes '&' wxString text = GetName(); SIZE sizeRect; ::GetTextExtentPoint32(hdc, text.c_str(), text.length(), &sizeRect); int flags = DST_PREFIXTEXT; if ( (stat & wxODDisabled) && !(stat & wxODSelected) ) flags |= DSS_DISABLED; if ( (stat & wxODHidePrefix) ) flags |= DSS_HIDEPREFIX; int x = rc.x + GetMarginWidth(); int y = rc.y + (rc.GetHeight() - sizeRect.cy) / 2; int cx = rc.GetWidth() - GetMarginWidth(); int cy = sizeRect.cy; ::DrawState(hdc, NULL, NULL, wxMSW_CONV_LPARAM(text), text.length(), x, y, cx, cy, flags); } // reset to default the font, colors and brush if (stat & wxODHasFocus) ::DrawFocusRect(hdc, &rect); return true; }
bool wxMenuItem::OnDrawItem(wxDC& dc, const wxRect& rc, wxODAction WXUNUSED(act), wxODStatus stat) { const MenuDrawData* data = MenuDrawData::Get(); wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); HDC hdc = GetHdcOf(*impl); RECT rect; wxCopyRectToRECT(rc, rect); int imgWidth = wxMax(GetMarginWidth(), data->CheckSize.cx); if ( IsOwnerDrawn() ) { // font and colors to use wxFont font; GetFontToUse(font); wxColour colText, colBack; GetColourToUse(stat, colText, colBack); // calculate metrics of item parts RECT rcSelection = rect; data->ItemMargin.ApplyTo(rcSelection); RECT rcSeparator = rcSelection; data->SeparatorMargin.ApplyTo(rcSeparator); RECT rcGutter = rcSelection; rcGutter.right = data->ItemMargin.cxLeftWidth + data->CheckBgMargin.cxLeftWidth + data->CheckMargin.cxLeftWidth + imgWidth + data->CheckMargin.cxRightWidth + data->CheckBgMargin.cxRightWidth; RECT rcText = rcSelection; rcText.left = rcGutter.right + data->TextBorder; // we draw the text label vertically centered, but this results in it // being 1px too low compared to native menus for some reason, fix it if ( data->MenuLayout() != MenuDrawData::FullTheme ) rcText.top--; #if wxUSE_UXTHEME // If a custom background colour is explicitly specified, we should use // it instead of the default theme background. wxUxThemeEngine* const theme = GetBackgroundColour().IsOk() ? NULL : MenuDrawData::GetUxThemeEngine(); if ( theme ) { POPUPITEMSTATES state; if ( stat & wxODDisabled ) { state = (stat & wxODSelected) ? MPI_DISABLEDHOT : MPI_DISABLED; } else if ( stat & wxODSelected ) { state = MPI_HOT; } else { state = MPI_NORMAL; } wxUxThemeHandle hTheme(GetMenu()->GetWindow(), L"MENU"); if ( theme->IsThemeBackgroundPartiallyTransparent(hTheme, MENU_POPUPITEM, state) ) { theme->DrawThemeBackground(hTheme, hdc, MENU_POPUPBACKGROUND, 0, &rect, NULL); } theme->DrawThemeBackground(hTheme, hdc, MENU_POPUPGUTTER, 0, &rcGutter, NULL); if ( IsSeparator() ) { rcSeparator.left = rcGutter.right; theme->DrawThemeBackground(hTheme, hdc, MENU_POPUPSEPARATOR, 0, &rcSeparator, NULL); return true; } theme->DrawThemeBackground(hTheme, hdc, MENU_POPUPITEM, state, &rcSelection, NULL); } else #endif // wxUSE_UXTHEME { if ( IsSeparator() ) { DrawEdge(hdc, &rcSeparator, EDGE_ETCHED, BF_TOP); return true; } AutoHBRUSH hbr(colBack.GetPixel()); SelectInHDC selBrush(hdc, hbr); ::FillRect(hdc, &rcSelection, hbr); } // draw text label // using native API because it recognizes '&' HDCTextColChanger changeTextCol(hdc, colText.GetPixel()); HDCBgColChanger changeBgCol(hdc, colBack.GetPixel()); HDCBgModeChanger changeBgMode(hdc, TRANSPARENT); SelectInHDC selFont(hdc, GetHfontOf(font)); // item text name without mnemonic for calculating size wxString text = GetName(); SIZE textSize; ::GetTextExtentPoint32(hdc, text.c_str(), text.length(), &textSize); // item text name with mnemonic text = GetItemLabel().BeforeFirst('\t'); int flags = DST_PREFIXTEXT; // themes menu is using specified color for disabled labels if ( data->MenuLayout() == MenuDrawData::Classic && (stat & wxODDisabled) && !(stat & wxODSelected) ) flags |= DSS_DISABLED; if ( (stat & wxODHidePrefix) && !data->AlwaysShowCues ) flags |= DSS_HIDEPREFIX; int x = rcText.left; int y = rcText.top + (rcText.bottom - rcText.top - textSize.cy) / 2; ::DrawState(hdc, NULL, NULL, wxMSW_CONV_LPARAM(text), text.length(), x, y, 0, 0, flags); // ::SetTextAlign(hdc, TA_RIGHT) doesn't work with DSS_DISABLED or DSS_MONO // as the last parameter in DrawState() (at least with Windows98). So we have // to take care of right alignment ourselves. wxString accel = GetItemLabel().AfterFirst(wxT('\t')); if ( !accel.empty() ) { SIZE accelSize; ::GetTextExtentPoint32(hdc, accel.c_str(), accel.length(), &accelSize); flags = DST_TEXT; // themes menu is using specified color for disabled labels if ( data->MenuLayout() == MenuDrawData::Classic && (stat & wxODDisabled) && !(stat & wxODSelected) ) flags |= DSS_DISABLED; x = rcText.right - data->ArrowMargin.GetTotalX() - data->ArrowSize.cx - data->ArrowBorder; // right align accel on FullTheme menu, left otherwise if ( data->MenuLayout() == MenuDrawData::FullTheme) x -= accelSize.cx; else x -= m_parentMenu->GetMaxAccelWidth(); y = rcText.top + (rcText.bottom - rcText.top - accelSize.cy) / 2; ::DrawState(hdc, NULL, NULL, wxMSW_CONV_LPARAM(accel), accel.length(), x, y, 0, 0, flags); } } // draw the bitmap RECT rcImg; SetRect(&rcImg, rect.left + data->ItemMargin.cxLeftWidth + data->CheckBgMargin.cxLeftWidth + data->CheckMargin.cxLeftWidth, rect.top + data->ItemMargin.cyTopHeight + data->CheckBgMargin.cyTopHeight + data->CheckMargin.cyTopHeight, rect.left + data->ItemMargin.cxLeftWidth + data->CheckBgMargin.cxLeftWidth + data->CheckMargin.cxLeftWidth + imgWidth, rect.bottom - data->ItemMargin.cyBottomHeight - data->CheckBgMargin.cyBottomHeight - data->CheckMargin.cyBottomHeight); if ( IsCheckable() && !m_bmpChecked.IsOk() ) { if ( stat & wxODChecked ) { DrawStdCheckMark((WXHDC)hdc, &rcImg, stat); } } else { wxBitmap bmp; if ( stat & wxODDisabled ) { bmp = GetDisabledBitmap(); } if ( !bmp.IsOk() ) { // for not checkable bitmaps we should always use unchecked one // because their checked bitmap is not set bmp = GetBitmap(!IsCheckable() || (stat & wxODChecked)); #if wxUSE_IMAGE if ( bmp.IsOk() && stat & wxODDisabled ) { // we need to grey out the bitmap as we don't have any specific // disabled bitmap wxImage imgGrey = bmp.ConvertToImage().ConvertToGreyscale(); if ( imgGrey.IsOk() ) bmp = wxBitmap(imgGrey); } #endif // wxUSE_IMAGE } if ( bmp.IsOk() ) { wxMemoryDC dcMem(&dc); dcMem.SelectObjectAsSource(bmp); // center bitmap int nBmpWidth = bmp.GetWidth(), nBmpHeight = bmp.GetHeight(); int x = rcImg.left + (imgWidth - nBmpWidth) / 2; int y = rcImg.top + (rcImg.bottom - rcImg.top - nBmpHeight) / 2; dc.Blit(x, y, nBmpWidth, nBmpHeight, &dcMem, 0, 0, wxCOPY, true); } } return true; }