- 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
diff --git a/dlls/comctl32/comboex.c b/dlls/comctl32/comboex.c
index 9422d1d..09d6ea5 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 @@
} 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 @@
* 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 @@
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_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_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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
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: