From 43230a2f42e9f53b84e0622a97464207655b9be1 Mon Sep 17 00:00:00 2001 From: "Dimitrie O. Paun" Date: Mon, 8 Apr 2002 20:16:01 +0000 Subject: [PATCH] - fix indentation - handle all out-of-memory cases - better drawing code - fix CBES_EX_NOEDITIMAGE handling - implement CBES_EX_NOEDITIMAGEINDENT - implement I_{INDENT,IMAGE}CALLBACK - fix notification code for ANSI/Unicode - make use of iOverlay image --- dlls/comctl32/comboex.c | 319 +++++++++++++++++++++++++----------------------- 1 file changed, 169 insertions(+), 150 deletions(-) diff --git a/dlls/comctl32/comboex.c b/dlls/comctl32/comboex.c index 9422d1de48c..09d6ea510a0 100644 --- a/dlls/comctl32/comboex.c +++ b/dlls/comctl32/comboex.c @@ -19,21 +19,14 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * TODO <------------- - * 1. The following extended styles need to be implemented, use will - * result in a FIXME: - * CBES_EX_NOEDITIMAGEINDENT + * FIXME: + * 1. Implement following extended styles: * CBES_EX_PATHWORDBREAKPROC * CBES_EX_NOSIZELIMIT * CBES_EX_CASESENSITIVE - * 2. None of the following callback items are implemented. Therefor - * no CBEN_GETDISPINFO notifies are issued. Use in either CBEM_INSERTITEM - * or CBEM_SETITEM will result in a FIXME: + * 2. Implement the following callbacks: * LPSTR_TEXTCALLBACK - * I_IMAGECALLBACK - * I_INDENTCALLBACK - * 3. No use is made of the iOverlay image. - * 4. Notify CBEN_DRAGBEGIN is not implemented. + * 3. Notify CBEN_DRAGBEGIN is not implemented. * */ @@ -44,11 +37,6 @@ #include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(comboex); -/* - * The following is necessary for the test done in COMBOEX_DrawItem - * to determine whether to dump out the DRAWITEM structure or not. - */ -WINE_DECLARE_DEBUG_CHANNEL(message); /* Item structure */ typedef struct @@ -86,16 +74,16 @@ typedef struct } COMBOEX_INFO; /* internal flags in the COMBOEX_INFO structure */ -#define WCBE_ACTEDIT 0x00000001 /* Edit active i.e. +#define WCBE_ACTEDIT 0x00000001 /* Edit active i.e. * CBEN_BEGINEDIT issued * but CBEN_ENDEDIT{A|W} * not yet issued. */ -#define WCBE_EDITCHG 0x00000002 /* Edit issued EN_CHANGE */ -#define WCBE_EDITHASCHANGED (WCBE_ACTEDIT | WCBE_EDITCHG) -#define WCBE_EDITFOCUSED 0x00000004 /* Edit control has focus */ +#define WCBE_EDITCHG 0x00000002 /* Edit issued EN_CHANGE */ +#define WCBE_EDITHASCHANGED (WCBE_ACTEDIT | WCBE_EDITCHG) +#define WCBE_EDITFOCUSED 0x00000004 /* Edit control has focus */ -#define ID_CB_EDIT 1001 +#define ID_CB_EDIT 1001 /* @@ -108,23 +96,23 @@ typedef struct * We really cannot use the ODS_COMBOBOXEDIT flag because MSDN states that * only version 4.0 applications will have ODS_COMBOBOXEDIT set. */ -#define ODS_COMBOEXLBOX 0x4000 +#define ODS_COMBOEXLBOX 0x4000 /* Height in pixels of control over the amount of the selected font */ -#define CBE_EXTRA 3 +#define CBE_EXTRA 3 /* Indent amount per MS documentation */ -#define CBE_INDENT 10 +#define CBE_INDENT 10 /* Offset in pixels from left side for start of image or text */ -#define CBE_STARTOFFSET 6 +#define CBE_STARTOFFSET 6 /* Offset between image and text */ -#define CBE_SEP 4 +#define CBE_SEP 4 -#define COMBOEX_SUBCLASS_PROP "CCComboEx32SubclassInfo" +#define COMBOEX_SUBCLASS_PROP "CCComboEx32SubclassInfo" #define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongW (hwnd, 0)) @@ -133,6 +121,7 @@ static LRESULT WINAPI COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT WINAPI COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr); static void COMBOEX_DumpItem (CBE_ITEMDATA *item) { @@ -184,39 +173,33 @@ static INT COMBOEX_Notify (COMBOEX_INFO *infoPtr, INT code, NMHDR *hdr) static INT COMBOEX_NotifyItem (COMBOEX_INFO *infoPtr, INT code, NMCOMBOBOXEXW *hdr) { - /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */ - - hdr->hdr.idFrom = GetDlgCtrlID (infoPtr->hwndSelf); - hdr->hdr.hwndFrom = infoPtr->hwndSelf; - hdr->hdr.code = code; if (infoPtr->NtfUnicode) - return SendMessageW (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0, - (LPARAM)hdr); + return COMBOEX_Notify (infoPtr, code, (NMHDR *)hdr); else { - LPWSTR str, ostr = NULL; + LPWSTR wstr = hdr->ceItem.pszText; + LPSTR astr = 0; INT ret, len = 0; - if (hdr->ceItem.mask & CBEIF_TEXT) { - ostr = hdr->ceItem.pszText; - str = ostr; - if (!str) str = (LPWSTR)L""; - len = WideCharToMultiByte (CP_ACP, 0, str, -1, 0, 0, NULL, NULL); + if ((hdr->ceItem.mask & CBEIF_TEXT) && wstr && wstr != LPSTR_TEXTCALLBACKW) { + len = WideCharToMultiByte (CP_ACP, 0, wstr, -1, 0, 0, NULL, NULL); if (len > 0) { - hdr->ceItem.pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(CHAR)); - //FIXME: what if alloc failed? - WideCharToMultiByte (CP_ACP, 0, str, -1, (LPSTR)hdr->ceItem.pszText, - len, NULL, NULL); + astr = (LPSTR)COMCTL32_Alloc ((len + 1)*sizeof(CHAR)); + if (!astr) return 0; + hdr->ceItem.pszText = (LPWSTR)astr; + WideCharToMultiByte (CP_ACP, 0, wstr, -1, astr, len, 0, 0); } } - ret = SendMessageA (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0, - (LPARAM)hdr); - if (hdr->ceItem.mask & CBEIF_TEXT) { - if (len > 0) - COMCTL32_Free (hdr->ceItem.pszText); - hdr->ceItem.pszText = ostr; - } + if (code == CBEN_ENDEDITW) code = CBEN_ENDEDITA; + else if (code == CBEN_GETDISPINFOW) code = CBEN_GETDISPINFOA; + else if (code == CBEN_DRAGBEGINW) code = CBEN_DRAGBEGINA; + + ret = COMBOEX_Notify (infoPtr, code, (NMHDR *)hdr); + + if (astr) COMCTL32_Free(astr); + if (!(code == CBEN_GETDISPINFOA && hdr->ceItem.mask & CBEIF_TEXT)) + hdr->ceItem.pszText = wstr; return ret; } } @@ -296,17 +279,18 @@ static void COMBOEX_CopyItem (CBE_ITEMDATA *item, COMBOBOXEXITEMW *cit) static void COMBOEX_AdjustEditPos (COMBOEX_INFO *infoPtr) { SIZE mysize; - IMAGEINFO iinfo; - INT x, y, w, h, xoff = 0; + INT x, y, w, h, xioff; RECT rect; if (!infoPtr->hwndEdit) return; - iinfo.rcImage.left = iinfo.rcImage.right = 0; - if (infoPtr->himl) { + if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) { + IMAGEINFO iinfo; + iinfo.rcImage.left = iinfo.rcImage.right = 0; ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo); - xoff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP; - } + xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP; + } else xioff = 0; + GetClientRect (infoPtr->hwndCombo, &rect); InflateRect (&rect, -2, -2); InvalidateRect (infoPtr->hwndCombo, &rect, TRUE); @@ -314,7 +298,7 @@ static void COMBOEX_AdjustEditPos (COMBOEX_INFO *infoPtr) /* reposition the Edit control based on whether icon exists */ COMBOEX_GetComboFontSize (infoPtr, &mysize); TRACE("Combo font x=%ld, y=%ld\n", mysize.cx, mysize.cy); - x = xoff + CBE_STARTOFFSET + 1; + x = xioff + CBE_STARTOFFSET + 1; w = rect.right-rect.left - x - GetSystemMetrics(SM_CXVSCROLL) - 1; h = mysize.cy + 1; y = rect.bottom - h - 1; @@ -402,8 +386,6 @@ static void COMBOEX_WarnCallBack (CBE_ITEMDATA *item) FIXME("Callback not implemented yet for iSelectedImage\n"); if (item->iOverlay == I_IMAGECALLBACK) FIXME("Callback not implemented yet for iOverlay\n"); - if (item->iIndent == I_INDENTCALLBACK) - FIXME("Callback not implemented yet for iIndent\n"); } @@ -534,7 +516,10 @@ static INT COMBOEX_InsertItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit) len = strlenW (str); if (len > 0) { item->pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR)); - //FIXME: what if allocation fails? + if (!item->pszText) { + COMCTL32_Free(item); + return -1; + } strcpyW (item->pszText, str); } else @@ -603,8 +588,7 @@ COMBOEX_SetExtendedStyle (COMBOEX_INFO *infoPtr, DWORD mask, DWORD style) dwTemp = infoPtr->dwExtStyle; - if (style & (CBES_EX_NOEDITIMAGEINDENT | - CBES_EX_PATHWORDBREAKPROC | + if (style & (CBES_EX_PATHWORDBREAKPROC | CBES_EX_NOSIZELIMIT | CBES_EX_CASESENSITIVE)) FIXME("Extended style not implemented %08lx\n", style); @@ -614,11 +598,9 @@ COMBOEX_SetExtendedStyle (COMBOEX_INFO *infoPtr, DWORD mask, DWORD style) else infoPtr->dwExtStyle = style; - /* - * native does this for CBES_EX_NOEDITIMAGE state change - */ - if ((infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE) ^ - (dwTemp & CBES_EX_NOEDITIMAGE)) { + /* test if the control's appearance has changed */ + mask = CBES_EX_NOEDITIMAGE | CBES_EX_NOEDITIMAGEINDENT; + if ((infoPtr->dwExtStyle & mask) != (dwTemp & mask)) { /* if state of EX_NOEDITIMAGE changes, invalidate all */ TRACE("EX_NOEDITIMAGE state changed to %ld\n", infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE); @@ -1033,7 +1015,10 @@ static LRESULT COMBOEX_Create (HWND hwnd, LPCREATESTRUCTA cs) * EDIT control. It is allocated zero-filled. */ infoPtr->edit = (CBE_ITEMDATA *)COMCTL32_Alloc (sizeof (CBE_ITEMDATA)); - //FIXME: what if allocation failed? + if (!infoPtr->edit) { + COMBOEX_Destroy(infoPtr); + return -1; + } return 0; } @@ -1266,26 +1251,21 @@ static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT *dis) SIZE txtsize; RECT rect; LPCWSTR str = nil; - int drawimage, drawstate; UINT xbase, x, y; - UINT xioff = 0; /* size and spacer of image if any */ - IMAGEINFO iinfo; INT len; COLORREF nbkc, ntxc, bkc, txc; + int drawimage, drawstate, xioff; if (!IsWindowEnabled(infoPtr->hwndCombo)) return 0; - /* dump the DRAWITEMSTRUCT if tracing "comboex" but not "message" */ - if (!TRACE_ON(message)) { - TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n", - dis->CtlType, dis->CtlID); - TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n", - dis->itemID, dis->itemAction, dis->itemState); - TRACE("hWnd=0x%04x hDC=0x%04x (%d,%d)-(%d,%d) itemData=0x%08lx\n", - dis->hwndItem, dis->hDC, dis->rcItem.left, - dis->rcItem.top, dis->rcItem.right, dis->rcItem.bottom, - dis->itemData); - } + TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n", + dis->CtlType, dis->CtlID); + TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n", + dis->itemID, dis->itemAction, dis->itemState); + TRACE("hWnd=0x%04x hDC=0x%04x (%d,%d)-(%d,%d) itemData=0x%08lx\n", + dis->hwndItem, dis->hDC, dis->rcItem.left, + dis->rcItem.top, dis->rcItem.right, dis->rcItem.bottom, + dis->itemData); /* MSDN says: */ /* "itemID - Specifies the menu item identifier for a menu */ @@ -1349,8 +1329,8 @@ static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT *dis) if( (len = GetWindowTextLengthW(infoPtr->hwndEdit)) ) { item->mask |= CBEIF_TEXT; item->pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR)); - //FIXME: what if alloc failed? - GetWindowTextW(infoPtr->hwndEdit, item->pszText, len+1); + if (item->pszText) + GetWindowTextW(infoPtr->hwndEdit, item->pszText, len+1); TRACE("edit control hwndEdit=%0x, text len=%d str=%s\n", infoPtr->hwndEdit, len, debugstr_w(item->pszText)); @@ -1372,13 +1352,61 @@ static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT *dis) if (TRACE_ON(comboex)) COMBOEX_DumpItem (item); xbase = CBE_STARTOFFSET; - if ((item->mask & CBEIF_INDENT) && (dis->itemState & ODS_COMBOEXLBOX)) - xbase += (item->iIndent * CBE_INDENT); - if (item->mask & CBEIF_IMAGE) { - ImageList_GetImageInfo(infoPtr->himl, item->iImage, &iinfo); - xioff = (iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP); + if ((item->mask & CBEIF_INDENT) && (dis->itemState & ODS_COMBOEXLBOX)) { + INT indent = item->iIndent; + if (indent == I_INDENTCALLBACK) { + NMCOMBOBOXEXW nmce; + ZeroMemory(&nmce, sizeof(nmce)); + nmce.ceItem.mask = CBEIF_INDENT; + COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); + if (nmce.ceItem.mask & CBEIF_DI_SETITEM) + item->iIndent = nmce.ceItem.iIndent; + indent = nmce.ceItem.iIndent; + } + xbase += (indent * CBE_INDENT); + } + + drawimage = -2; + drawstate = ILD_NORMAL; + if (item->mask & CBEIF_IMAGE) + drawimage = item->iImage; + if (dis->itemState & ODS_COMBOEXLBOX) { + /* drawing listbox entry */ + if (dis->itemState & ODS_SELECTED) { + if (item->mask & CBEIF_SELECTEDIMAGE) + drawimage = item->iSelectedImage; + drawstate = ILD_SELECTED; + } + } else { + /* drawing combo/edit entry */ + if (IsWindowVisible(infoPtr->hwndEdit)) { + /* if we have an edit control, the slave the + * selection state to the Edit focus state + */ + if (infoPtr->flags & WCBE_EDITFOCUSED) { + if (item->mask & CBEIF_SELECTEDIMAGE) + drawimage = item->iSelectedImage; + drawstate = ILD_SELECTED; + } + } else { + /* if we don't have an edit control, use + * the requested state. + */ + if (dis->itemState & ODS_SELECTED) { + if (item->mask & CBEIF_SELECTEDIMAGE) + drawimage = item->iSelectedImage; + drawstate = ILD_SELECTED; + } + } } + if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) { + IMAGEINFO iinfo; + iinfo.rcImage.left = iinfo.rcImage.right = 0; + ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo); + xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP; + } else xioff = 0; + /* setup pointer to text to be drawn */ if (item && (item->mask & CBEIF_TEXT) && item->pszText) str = item->pszText; @@ -1389,70 +1417,60 @@ static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT *dis) GetTextExtentPoint32W (dis->hDC, str, len, &txtsize); if (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) { - drawimage = -1; - drawstate = ILD_NORMAL; - if (!(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE)) { - if (item->mask & CBEIF_IMAGE) - drawimage = item->iImage; - if (dis->itemState & ODS_COMBOEXLBOX) { - /* drawing listbox entry */ - if (dis->itemState & ODS_SELECTED) { - if (item->mask & CBEIF_SELECTEDIMAGE) - drawimage = item->iSelectedImage; - drawstate = ILD_SELECTED; - } - } - else { - /* drawing combo/edit entry */ - if (IsWindowVisible(infoPtr->hwndEdit)) { - /* if we have an edit control, the slave the - * selection state to the Edit focus state - */ - if (infoPtr->flags & WCBE_EDITFOCUSED) { - if (item->mask & CBEIF_SELECTEDIMAGE) - drawimage = item->iSelectedImage; - drawstate = ILD_SELECTED; - } - } - else { - /* if we don't have an edit control, use - * the requested state. - */ - if (dis->itemState & ODS_SELECTED) { - if (item->mask & CBEIF_SELECTEDIMAGE) - drawimage = item->iSelectedImage; - drawstate = ILD_SELECTED; - } - } - } + int overlay = item->iOverlay; + + if (drawimage == I_IMAGECALLBACK) { + NMCOMBOBOXEXW nmce; + ZeroMemory(&nmce, sizeof(nmce)); + nmce.ceItem.mask = (drawstate == ILD_NORMAL) ? CBEIF_IMAGE : CBEIF_SELECTEDIMAGE; + COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); + if (drawstate == ILD_NORMAL) { + if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iImage = nmce.ceItem.iImage; + drawimage = nmce.ceItem.iImage; + } else if (drawstate == ILD_SELECTED) { + if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iSelectedImage = nmce.ceItem.iSelectedImage; + drawimage = nmce.ceItem.iSelectedImage; + } else ERR("Bad draw state = %d\n", drawstate); + } + + if (overlay == I_IMAGECALLBACK) { + NMCOMBOBOXEXW nmce; + ZeroMemory(&nmce, sizeof(nmce)); + nmce.ceItem.mask = CBEIF_OVERLAY; + COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); + if (nmce.ceItem.mask & CBEIF_DI_SETITEM) + item->iOverlay = nmce.ceItem.iOverlay; + overlay = nmce.ceItem.iOverlay; } - if (drawimage != -1) { - TRACE("drawing image state=%d\n", dis->itemState & ODS_SELECTED); - ImageList_Draw (infoPtr->himl, drawimage, dis->hDC, - xbase, dis->rcItem.top, drawstate); + + if (drawimage >= 0 && + !(infoPtr->dwExtStyle & (CBES_EX_NOEDITIMAGE | CBES_EX_NOEDITIMAGEINDENT))) { + if (overlay > 0) ImageList_SetOverlayImage (infoPtr->himl, overlay, 1); + ImageList_Draw (infoPtr->himl, drawimage, dis->hDC, xbase, dis->rcItem.top, + drawstate | (overlay > 0 ? INDEXTOOVERLAYMASK(1) : 0)); } /* now draw the text */ if (!IsWindowVisible (infoPtr->hwndEdit)) { - nbkc = GetSysColor ((dis->itemState & ODS_SELECTED) ? - COLOR_HIGHLIGHT : COLOR_WINDOW); - bkc = SetBkColor (dis->hDC, nbkc); - ntxc = GetSysColor ((dis->itemState & ODS_SELECTED) ? - COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT); - txc = SetTextColor (dis->hDC, ntxc); - x = xbase + xioff; - y = dis->rcItem.top + - (dis->rcItem.bottom - dis->rcItem.top - txtsize.cy) / 2; - rect.left = x; - rect.right = x + txtsize.cx; - rect.top = dis->rcItem.top + 1; - rect.bottom = dis->rcItem.bottom - 1; - TRACE("drawing item %d text, rect=(%d,%d)-(%d,%d)\n", - dis->itemID, rect.left, rect.top, rect.right, rect.bottom); - ExtTextOutW (dis->hDC, x, y, ETO_OPAQUE | ETO_CLIPPED, - &rect, str, len, 0); - SetBkColor (dis->hDC, bkc); - SetTextColor (dis->hDC, txc); + nbkc = GetSysColor ((dis->itemState & ODS_SELECTED) ? + COLOR_HIGHLIGHT : COLOR_WINDOW); + bkc = SetBkColor (dis->hDC, nbkc); + ntxc = GetSysColor ((dis->itemState & ODS_SELECTED) ? + COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT); + txc = SetTextColor (dis->hDC, ntxc); + x = xbase + xioff; + y = dis->rcItem.top + + (dis->rcItem.bottom - dis->rcItem.top - txtsize.cy) / 2; + rect.left = x; + rect.right = x + txtsize.cx; + rect.top = dis->rcItem.top + 1; + rect.bottom = dis->rcItem.bottom - 1; + TRACE("drawing item %d text, rect=(%d,%d)-(%d,%d)\n", + dis->itemID, rect.left, rect.top, rect.right, rect.bottom); + ExtTextOutW (dis->hDC, x, y, ETO_OPAQUE | ETO_CLIPPED, + &rect, str, len, 0); + SetBkColor (dis->hDC, bkc); + SetTextColor (dis->hDC, txc); } } @@ -2098,7 +2116,8 @@ COMBOEX_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case CBEM_SETUNICODEFORMAT: return COMBOEX_SetUnicodeFormat (infoPtr, wParam); - /* case CBEM_SETWINDOWTHEME: FIXME */ + /*case CBEM_SETWINDOWTHEME: + FIXME("CBEM_SETWINDOWTHEME: stub\n");*/ /* Combo messages we are not sure if we need to process or just forward */ case CB_GETDROPPEDCONTROLRECT: -- 2.11.4.GIT