- Minor API files fixes
[wine/multimedia.git] / dlls / comctl32 / comboex.c
blob0f3e08e98d924bc01ec3276f63756de2626d1999
1 /*
2 * ComboBoxEx control v2 (mod3)
4 * Copyright 1998, 1999 Eric Kohl
6 * NOTES
7 * This is just a dummy control. An author is needed! Any volunteers?
8 * I will only improve this control once in a while.
9 * Eric <ekohl@abo.rhein-zeitung.de>
11 * TODO:
12 * - All messages.
13 * - All notifications.
15 * FIXME:
16 * - should include "combo.h"
18 * Changes Guy Albertelli <galberte@neo.lrun.com>
19 * v1 Implemented messages: CB_SETITEMHEIGHT, WM_WINDOWPOSCHANGING,
20 * WM_DRAWITEM, and WM_MEASUREITEM. Fixed WM_CREATE. Fixed height
21 * of window rect reported fixing rebar control.
22 * v2
23 * 1. Rewrite of WM_Create for own created EDIT control. Also try to
24 * generate message sequence similar to native DLL.
25 * 2. Handle case where CBEM_SETITEM is called to display data in EDIT
26 * Control.
27 * 3. Add override for WNDPROC for the EDIT control (reqed for VK_RETURN).
28 * 4. Dump input data for things using COMBOBOXEXITEM{A|W}.
29 * 5. Handle positioning EDIT control based on whether icon present.
30 * 6. Make InsertItemA use InsertItemW, and store all data in ..W form.
31 * 7. Implement CB_SETCURSEL.
32 * 8. Add override for WNDPROC for the COMBO control.
34 * Test vehicals were the ControlSpy modules (rebar.exe and comboboxex.exe),
35 * and IE 4.0.
39 #include <string.h>
40 #include "winbase.h"
41 #include "commctrl.h"
42 #include "debugtools.h"
43 #include "wine/unicode.h"
45 DEFAULT_DEBUG_CHANNEL(comboex);
47 * The following is necessary for the test done in COMBOEX_DrawItem
48 * to determine whether to dump out the DRAWITEM structure or not.
50 DECLARE_DEBUG_CHANNEL(message);
52 /* Item structure */
53 typedef struct
55 VOID *next;
56 UINT mask;
57 LPWSTR pszText;
58 int cchTextMax;
59 int iImage;
60 int iSelectedImage;
61 int iOverlay;
62 int iIndent;
63 LPARAM lParam;
64 } CBE_ITEMDATA;
66 /* ComboBoxEx structure */
67 typedef struct
69 HIMAGELIST himl;
70 HWND hwndSelf; /* my own hwnd */
71 HWND hwndCombo;
72 HWND hwndEdit;
73 WNDPROC prevEditWndProc; /* previous Edit WNDPROC value */
74 WNDPROC prevComboWndProc; /* previous Combo WNDPROC value */
75 DWORD dwExtStyle;
76 DWORD flags; /* WINE internal flags */
77 HFONT font;
78 INT nb_items; /* Number of items */
79 CBE_ITEMDATA *edit; /* item data for edit item */
80 CBE_ITEMDATA *items; /* Array of items */
81 } COMBOEX_INFO;
83 /* internal flags in the COMBOEX_INFO structure */
84 #define WCBE_ACTEDIT 0x00000001 /* Edit active i.e.
85 * CBEN_BEGINEDIT issued
86 * but CBEN_ENDEDIT{A|W}
87 * not yet issued. */
91 #define ID_CB_EDIT 1001
93 /* Height in pixels of control over the amount of the selected font */
94 #define CBE_EXTRA 3
96 /* Indent amount per MS documentation */
97 #define CBE_INDENT 10
99 /* Offset in pixels from left side for start of image or text */
100 #define CBE_STARTOFFSET 6
102 /* Offset between image and text */
103 #define CBE_SEP 4
105 #define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongA (hwnd, 0))
108 /* Things common to the entire DLL */
109 static ATOM ComboExInfo;
110 static LRESULT WINAPI
111 COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
112 static LRESULT WINAPI
113 COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
115 static void
116 COMBOEX_DumpItem (CBE_ITEMDATA *item)
118 if (TRACE_ON(comboex)){
119 TRACE("item %p - mask=%08x, pszText=%p, cchTM=%d, iImage=%d\n",
120 item, item->mask, item->pszText, item->cchTextMax,
121 item->iImage);
122 TRACE("item %p - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
123 item, item->iSelectedImage, item->iOverlay, item->iIndent, item->lParam);
124 if ((item->mask & CBEIF_TEXT) && item->pszText)
125 TRACE("item %p - pszText=%s\n",
126 item, debugstr_w((const WCHAR *)item->pszText));
131 static void
132 COMBOEX_DumpInput (COMBOBOXEXITEMA *input, BOOL true_for_w)
134 if (TRACE_ON(comboex)){
135 TRACE("input - mask=%08x, iItem=%d, pszText=%p, cchTM=%d, iImage=%d\n",
136 input->mask, input->iItem, input->pszText, input->cchTextMax,
137 input->iImage);
138 if ((input->mask & CBEIF_TEXT) && input->pszText) {
139 if (true_for_w)
140 TRACE("input - pszText=<%s>\n",
141 debugstr_w((const WCHAR *)input->pszText));
142 else
143 TRACE("input - pszText=<%s>\n",
144 debugstr_a((const char *)input->pszText));
146 TRACE("input - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n",
147 input->iSelectedImage, input->iOverlay, input->iIndent, input->lParam);
152 inline static LRESULT
153 COMBOEX_Forward (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
155 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
157 FIXME("(0x%x 0x%x 0x%lx): stub\n", uMsg, wParam, lParam);
159 if (infoPtr->hwndCombo)
160 return SendMessageA (infoPtr->hwndCombo, uMsg, wParam, lParam);
162 return 0;
166 static INT
167 COMBOEX_Notify (COMBOEX_INFO *infoPtr, INT code, NMHDR *hdr)
170 hdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
171 hdr->hwndFrom = infoPtr->hwndSelf;
172 hdr->code = code;
173 return SendMessageA (GetParent(infoPtr->hwndSelf), WM_NOTIFY, 0,
174 (LPARAM)hdr);
178 static void
179 COMBOEX_GetComboFontSize (COMBOEX_INFO *infoPtr, SIZE *size)
181 HFONT nfont, ofont;
182 HDC mydc;
184 mydc = GetDC (0); /* why the entire screen???? */
185 nfont = SendMessageA (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
186 ofont = (HFONT) SelectObject (mydc, nfont);
187 GetTextExtentPointA (mydc, "A", 1, size);
188 SelectObject (mydc, ofont);
189 ReleaseDC (0, mydc);
190 TRACE("selected font hwnd=%08x, height=%ld\n", nfont, size->cy);
194 static void
195 COMBOEX_AdjustEditPos (COMBOEX_INFO *infoPtr)
197 SIZE mysize;
198 IMAGEINFO iinfo;
199 INT x, y, w, h, xoff = 0;
200 RECT rect;
202 if (!infoPtr->hwndEdit) return;
203 iinfo.rcImage.left = iinfo.rcImage.right = 0;
204 if (infoPtr->himl) {
205 ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo);
206 xoff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP;
208 GetClientRect (infoPtr->hwndCombo, &rect);
209 InflateRect (&rect, -2, -2);
210 InvalidateRect (infoPtr->hwndCombo, &rect, TRUE);
212 /* reposition the Edit control based on whether icon exists */
213 COMBOEX_GetComboFontSize (infoPtr, &mysize);
214 TRACE("Combo font x=%ld, y=%ld\n", mysize.cx, mysize.cy);
215 x = xoff + CBE_STARTOFFSET;
216 y = CBE_EXTRA;
217 w = rect.right-rect.left - x - GetSystemMetrics(SM_CXVSCROLL) - 1;
218 h = mysize.cy + 1;
220 TRACE("Combo client (%d,%d)-(%d,%d), setting Edit to (%d,%d)-(%d,%d)\n",
221 rect.left, rect.top, rect.right, rect.bottom,
222 x, y, x + w, y + h);
223 SetWindowPos(infoPtr->hwndEdit, HWND_TOP,
224 x, y,
225 w, h,
226 SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
230 static void
231 COMBOEX_ReSize (HWND hwnd, COMBOEX_INFO *infoPtr)
233 SIZE mysize;
234 UINT cy;
235 IMAGEINFO iinfo;
237 COMBOEX_GetComboFontSize (infoPtr, &mysize);
238 cy = mysize.cy + CBE_EXTRA;
239 if (infoPtr->himl) {
240 ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo);
241 cy = max (iinfo.rcImage.bottom - iinfo.rcImage.top, cy);
242 TRACE("upgraded height due to image: height=%d\n", cy);
244 SendMessageA (hwnd, CB_SETITEMHEIGHT, (WPARAM) -1, (LPARAM) cy);
245 if (infoPtr->hwndCombo)
246 SendMessageA (infoPtr->hwndCombo, CB_SETITEMHEIGHT,
247 (WPARAM) 0, (LPARAM) cy);
251 static void
252 COMBOEX_SetEditText (COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item)
254 if (!infoPtr->hwndEdit) return;
255 /* native issues the following messages to the {Edit} control */
256 /* WM_SETTEXT (0,addr) */
257 /* EM_SETSEL32 (0,0) */
258 /* EM_SETSEL32 (0,-1) */
259 if (item->mask & CBEIF_TEXT) {
260 SendMessageW (infoPtr->hwndEdit, WM_SETTEXT, 0, (LPARAM)item->pszText);
261 SendMessageA (infoPtr->hwndEdit, EM_SETSEL, 0, 0);
262 SendMessageA (infoPtr->hwndEdit, EM_SETSEL, 0, -1);
267 static CBE_ITEMDATA *
268 COMBOEX_FindItem(COMBOEX_INFO *infoPtr, INT index)
270 CBE_ITEMDATA *item;
271 INT i;
273 if ((index > infoPtr->nb_items) || (index < -1))
274 return 0;
275 if (index == -1)
276 return infoPtr->edit;
277 item = infoPtr->items;
278 i = infoPtr->nb_items - 1;
280 /* find the item in the list */
281 while (item && (i > index)) {
282 item = (CBE_ITEMDATA *)item->next;
283 i--;
285 if (!item || (i != index)) {
286 FIXME("COMBOBOXEX item structures broken. Please report!\n");
287 return 0;
289 return item;
293 /* *** CBEM_xxx message support *** */
296 /* << COMBOEX_DeleteItem >> */
299 inline static LRESULT
300 COMBOEX_GetComboControl (HWND hwnd, WPARAM wParam, LPARAM lParam)
302 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
304 TRACE("\n");
306 return (LRESULT)infoPtr->hwndCombo;
310 inline static LRESULT
311 COMBOEX_GetEditControl (HWND hwnd, WPARAM wParam, LPARAM lParam)
313 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
315 if ((GetWindowLongA (hwnd, GWL_STYLE) & CBS_DROPDOWNLIST) != CBS_DROPDOWN)
316 return 0;
318 TRACE("-- 0x%x\n", infoPtr->hwndEdit);
320 return (LRESULT)infoPtr->hwndEdit;
324 inline static LRESULT
325 COMBOEX_GetExtendedStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
327 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
329 return (LRESULT)infoPtr->dwExtStyle;
333 inline static LRESULT
334 COMBOEX_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
336 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
338 TRACE("(0x%08x 0x%08lx)\n", wParam, lParam);
340 return (LRESULT)infoPtr->himl;
344 /* << COMBOEX_GetItemA >> */
346 /* << COMBOEX_GetItemW >> */
348 /* << COMBOEX_GetUniCodeFormat >> */
351 static LRESULT
352 COMBOEX_HasEditChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
354 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
356 if ((GetWindowLongA (hwnd, GWL_STYLE) & CBS_DROPDOWNLIST) != CBS_DROPDOWN)
357 return FALSE;
358 if (infoPtr->flags & WCBE_ACTEDIT)
359 /* FIXME: need to also test edit control */
360 return TRUE;
361 return FALSE;
365 static LRESULT
366 COMBOEX_InsertItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
368 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
369 COMBOBOXEXITEMW *cit = (COMBOBOXEXITEMW *) lParam;
370 INT index;
371 CBE_ITEMDATA *item;
373 COMBOEX_DumpInput ((COMBOBOXEXITEMA *) cit, TRUE);
375 /* get real index of item to insert */
376 index = cit->iItem;
377 if (index == -1) index = infoPtr->nb_items;
378 if (index > infoPtr->nb_items) index = infoPtr->nb_items;
380 /* get space and chain it in */
381 item = (CBE_ITEMDATA *)COMCTL32_Alloc (sizeof (CBE_ITEMDATA));
382 item->next = NULL;
383 item->pszText = NULL;
385 /* locate position to insert new item in */
386 if (index == infoPtr->nb_items) {
387 /* fast path for iItem = -1 */
388 item->next = infoPtr->items;
389 infoPtr->items = item;
391 else {
392 INT i = infoPtr->nb_items-1;
393 CBE_ITEMDATA *moving = infoPtr->items;
395 while ((i > index) && moving) {
396 moving = (CBE_ITEMDATA *)moving->next;
397 i--;
399 if (!moving) {
400 FIXME("COMBOBOXEX item structures broken. Please report!\n");
401 COMCTL32_Free(item);
402 return -1;
404 item->next = moving->next;
405 moving->next = item;
408 /* fill in our hidden item structure */
409 item->mask = cit->mask;
410 if (item->mask & CBEIF_TEXT) {
411 LPWSTR str;
412 INT len;
414 str = cit->pszText;
415 if (!str) str = (LPWSTR) L"";
416 len = strlenW (str);
417 if (len > 0) {
418 item->pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
419 strcpyW (item->pszText, str);
421 item->cchTextMax = cit->cchTextMax;
423 if (item->mask & CBEIF_IMAGE)
424 item->iImage = cit->iImage;
425 if (item->mask & CBEIF_SELECTEDIMAGE)
426 item->iSelectedImage = cit->iSelectedImage;
427 if (item->mask & CBEIF_OVERLAY)
428 item->iOverlay = cit->iOverlay;
429 if (item->mask & CBEIF_INDENT)
430 item->iIndent = cit->iIndent;
431 if (item->mask & CBEIF_LPARAM)
432 item->lParam = cit->lParam;
433 infoPtr->nb_items++;
435 COMBOEX_DumpItem (item);
437 SendMessageA (infoPtr->hwndCombo, CB_INSERTSTRING,
438 (WPARAM)cit->iItem, (LPARAM)item);
440 return index;
445 static LRESULT
446 COMBOEX_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
448 COMBOBOXEXITEMA *cit = (COMBOBOXEXITEMA *) lParam;
449 COMBOBOXEXITEMW citW;
450 LRESULT ret;
452 memcpy(&citW,cit,sizeof(COMBOBOXEXITEMA));
453 if (cit->mask & CBEIF_TEXT) {
454 LPSTR str;
455 INT len;
457 str = cit->pszText;
458 if (!str) str="";
459 len = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
460 if (len > 0) {
461 citW.pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
462 MultiByteToWideChar (CP_ACP, 0, str, -1, citW.pszText, len);
465 ret = COMBOEX_InsertItemW(hwnd,wParam,(LPARAM)&citW);;
467 if (cit->mask & CBEIF_TEXT)
468 COMCTL32_Free(citW.pszText);
469 return ret;
473 static LRESULT
474 COMBOEX_SetExtendedStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
476 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
477 DWORD dwTemp;
479 TRACE("(0x%08x 0x%08lx)\n", wParam, lParam);
481 dwTemp = infoPtr->dwExtStyle;
483 if ((DWORD)wParam) {
484 infoPtr->dwExtStyle = (infoPtr->dwExtStyle & ~(DWORD)wParam) | (DWORD)lParam;
486 else
487 infoPtr->dwExtStyle = (DWORD)lParam;
489 /* FIXME: repaint?? */
491 return (LRESULT)dwTemp;
495 inline static LRESULT
496 COMBOEX_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
498 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
499 HIMAGELIST himlTemp;
501 TRACE("(0x%08x 0x%08lx)\n", wParam, lParam);
503 himlTemp = infoPtr->himl;
504 infoPtr->himl = (HIMAGELIST)lParam;
506 COMBOEX_ReSize (hwnd, infoPtr);
507 InvalidateRect (infoPtr->hwndCombo, NULL, TRUE);
509 /* reposition the Edit control based on whether icon exists */
510 COMBOEX_AdjustEditPos (infoPtr);
511 return (LRESULT)himlTemp;
514 static LRESULT
515 COMBOEX_SetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
517 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
518 COMBOBOXEXITEMW *cit = (COMBOBOXEXITEMW *) lParam;
519 INT index;
520 CBE_ITEMDATA *item;
522 COMBOEX_DumpInput ((COMBOBOXEXITEMA *) cit, TRUE);
524 /* get real index of item to insert */
525 index = cit->iItem;
527 /* if item number requested does not exist then return failure */
528 if ((index > infoPtr->nb_items) || (index < -1)) {
529 ERR("attempt to set item that does not exist yet!\n");
530 return 0;
533 /* if the item is the edit control and there is no edit control, skip */
534 if ((index == -1) &&
535 ((GetWindowLongA (hwnd, GWL_STYLE) & CBS_DROPDOWNLIST) != CBS_DROPDOWN))
536 return 0;
538 if (!(item = COMBOEX_FindItem(infoPtr, index))) {
539 ERR("attempt to set item that was not found!\n");
540 return 0;
543 /* add/change stuff to the internal item structure */
544 item->mask |= cit->mask;
545 if (cit->mask & CBEIF_TEXT) {
546 LPWSTR str;
547 INT len;
548 WCHAR emptystr[1] = {0};
550 str = cit->pszText;
551 if (!str) str=emptystr;
552 len = strlenW(str);
553 if (len > 0) {
554 item->pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
555 strcpyW(item->pszText,str);
557 item->cchTextMax = cit->cchTextMax;
559 if (cit->mask & CBEIF_IMAGE)
560 item->iImage = cit->iImage;
561 if (cit->mask & CBEIF_SELECTEDIMAGE)
562 item->iSelectedImage = cit->iSelectedImage;
563 if (cit->mask & CBEIF_OVERLAY)
564 item->iOverlay = cit->iOverlay;
565 if (cit->mask & CBEIF_INDENT)
566 item->iIndent = cit->iIndent;
567 if (cit->mask & CBEIF_LPARAM)
568 cit->lParam = cit->lParam;
570 COMBOEX_DumpItem (item);
572 /* if original request was to update edit control, do some fast foot work */
573 if (cit->iItem == -1) {
574 COMBOEX_SetEditText (infoPtr, item);
575 RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | RDW_INVALIDATE);
577 return TRUE;
580 static LRESULT
581 COMBOEX_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
583 COMBOBOXEXITEMA *cit = (COMBOBOXEXITEMA *) lParam;
584 COMBOBOXEXITEMW citW;
585 LRESULT ret;
587 memcpy(&citW,cit,sizeof(COMBOBOXEXITEMA));
588 if (cit->mask & CBEIF_TEXT) {
589 LPSTR str;
590 INT len;
592 str = cit->pszText;
593 if (!str) str="";
594 len = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
595 if (len > 0) {
596 citW.pszText = (LPWSTR)COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
597 MultiByteToWideChar (CP_ACP, 0, str, -1, citW.pszText, len);
600 ret = COMBOEX_SetItemW(hwnd,wParam,(LPARAM)&citW);;
602 if (cit->mask & CBEIF_TEXT)
603 COMCTL32_Free(citW.pszText);
604 return ret;
608 /* << COMBOEX_SetUniCodeFormat >> */
611 /* *** CB_xxx message support *** */
614 static LRESULT
615 COMBOEX_SetCursel (HWND hwnd, WPARAM wParam, LPARAM lParam)
617 INT index = wParam;
618 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
619 CBE_ITEMDATA *item;
621 if (!(item = COMBOEX_FindItem(infoPtr, index))) {
622 /* FIXME: need to clear selection */
623 return CB_ERR;
626 TRACE("selecting item %d\n", index);
628 COMBOEX_SetEditText (infoPtr, item);
629 if (infoPtr->hwndCombo)
630 return SendMessageA (infoPtr->hwndCombo, CB_SETCURSEL, wParam, lParam);
631 return CB_ERR;
635 static LRESULT
636 COMBOEX_SetItemHeight (HWND hwnd, WPARAM wParam, LPARAM lParam)
638 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
639 RECT cb_wrect, cbx_wrect, cbx_crect;
640 LRESULT ret = 0;
641 UINT height;
643 /* First, lets forward the message to the normal combo control
644 just like Windows. */
645 if (infoPtr->hwndCombo)
646 SendMessageA (infoPtr->hwndCombo, CB_SETITEMHEIGHT, wParam, lParam);
648 GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
649 GetWindowRect (hwnd, &cbx_wrect);
650 GetClientRect (hwnd, &cbx_crect);
651 /* the height of comboex as height of the combo + comboex border */
652 height = cb_wrect.bottom-cb_wrect.top
653 + cbx_wrect.bottom-cbx_wrect.top
654 - (cbx_crect.bottom-cbx_crect.top);
655 TRACE("EX window=(%d,%d)-(%d,%d), client=(%d,%d)-(%d,%d)\n",
656 cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom,
657 cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom);
658 TRACE("CB window=(%d,%d)-(%d,%d), EX setting=(0,0)-(%d,%d)\n",
659 cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom,
660 cbx_wrect.right-cbx_wrect.left, height);
661 SetWindowPos (hwnd, HWND_TOP, 0, 0,
662 cbx_wrect.right-cbx_wrect.left,
663 height,
664 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
666 return ret;
670 /* *** WM_xxx message support *** */
673 static LRESULT
674 COMBOEX_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
676 LPCREATESTRUCTA cs = (LPCREATESTRUCTA) lParam;
677 COMBOEX_INFO *infoPtr;
678 DWORD dwComboStyle;
679 LOGFONTA mylogfont;
680 CBE_ITEMDATA *item;
681 RECT wnrc1, clrc1, cmbwrc;
682 LONG test;
684 /* allocate memory for info structure */
685 infoPtr = (COMBOEX_INFO *)COMCTL32_Alloc (sizeof(COMBOEX_INFO));
686 if (infoPtr == NULL) {
687 ERR("could not allocate info memory!\n");
688 return 0;
691 /* initialize info structure */
693 infoPtr->items = NULL;
694 infoPtr->nb_items = 0;
695 infoPtr->hwndSelf = hwnd;
697 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
699 /* create combo box */
700 dwComboStyle = GetWindowLongA (hwnd, GWL_STYLE) &
701 (CBS_SIMPLE|CBS_DROPDOWN|CBS_DROPDOWNLIST|WS_CHILD);
703 TRACE("combo style=%08lx, additional style=%08lx\n", dwComboStyle,
704 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL |
705 CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST |
706 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED);
708 /* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */
709 /* specified. It then creates it's own version of the EDIT control */
710 /* and makes the ComboBox the parent. This is because a normal */
711 /* DROPDOWNLIST does not have a EDIT control, but we need one. */
712 /* We also need to place the edit control at the proper location */
713 /* (allow space for the icons). */
715 infoPtr->hwndCombo = CreateWindowA ("ComboBox", "",
716 /* following line added to match native */
717 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL |
718 CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST |
719 /* was base and is necessary */
720 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | dwComboStyle,
721 cs->y, cs->x, cs->cx, cs->cy, hwnd,
722 /* (HMENU) GetWindowLongA (hwnd, GWL_ID), */
723 /* */ (HMENU) 0, /* */
724 GetWindowLongA (hwnd, GWL_HINSTANCE), NULL);
726 #if 0
727 /* ***** not needed any more ***** */
729 LPHEADCOMBO lphc;
731 * The following does not work (WIN98 or later) but we need
732 * the list box handle for later
733 * SendMessageA(infoPtr->hwndCombo, CB_GETCOMBOBOXINFO, 0,
734 * (LPARAM) &comboinfo);
735 * infoPtr->hwndLBox = comboinfo.hwndList;
737 * So we need to violate philosophical separation by the following
738 * code.
740 lphc = (LPHEADCOMBO) GetWindowLongA(infoPtr->hwndCombo, 0);
741 infoPtr->hwndLBox = lphc->hWndLBox;
742 if (!infoPtr->hwndLBox) {
743 ERR("error error listbox handle zero\n");
745 #endif
748 * native does the following at this point according to trace:
749 * GetWindowThreadProcessId(hwndCombo,0)
750 * GetCurrentThreadId()
751 * GetWindowThreadProcessId(hwndCombo, &???)
752 * GetCurrentProcessId()
756 * Setup a property to hold the pointer to the COMBOBOXEX
757 * data structure.
759 test = GetPropA(infoPtr->hwndCombo, (LPCSTR)(LONG)ComboExInfo);
760 if (!test || ((COMBOEX_INFO *)test != infoPtr)) {
761 SetPropA(infoPtr->hwndCombo, "CC32SubclassInfo", (LONG)infoPtr);
763 infoPtr->prevComboWndProc = (WNDPROC)SetWindowLongA(infoPtr->hwndCombo,
764 GWL_WNDPROC, (LONG)COMBOEX_ComboWndProc);
765 infoPtr->font = SendMessageA (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
769 * Now create our own EDIT control so we can position it.
770 * It is created only for CBS_DROPDOWN style
772 if ((cs->style & CBS_DROPDOWNLIST) == CBS_DROPDOWN) {
773 infoPtr->hwndEdit = CreateWindowExA (0, "EDIT", "",
774 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_AUTOHSCROLL,
775 0, 0, 0, 0, /* will set later */
776 infoPtr->hwndCombo,
777 (HMENU) GetWindowLongA (hwnd, GWL_ID),
778 GetWindowLongA (hwnd, GWL_HINSTANCE),
779 NULL);
781 /* native does the following at this point according to trace:
782 * GetWindowThreadProcessId(hwndEdit,0)
783 * GetCurrentThreadId()
784 * GetWindowThreadProcessId(hwndEdit, &???)
785 * GetCurrentProcessId()
789 * Setup a property to hold the pointer to the COMBOBOXEX
790 * data structure.
792 test = GetPropA(infoPtr->hwndEdit, (LPCSTR)(LONG)ComboExInfo);
793 if (!test || ((COMBOEX_INFO *)test != infoPtr)) {
794 SetPropA(infoPtr->hwndEdit, "CC32SubclassInfo", (LONG)infoPtr);
796 infoPtr->prevEditWndProc = (WNDPROC)SetWindowLongA(infoPtr->hwndEdit,
797 GWL_WNDPROC, (LONG)COMBOEX_EditWndProc);
798 infoPtr->font = SendMessageA (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
800 else {
801 infoPtr->hwndEdit = 0;
802 infoPtr->font = 0;
806 * Locate the default font if necessary and then set it in
807 * all associated controls
809 if (!infoPtr->font) {
810 SystemParametersInfoA (SPI_GETICONTITLELOGFONT, sizeof(mylogfont),
811 &mylogfont, 0);
812 infoPtr->font = CreateFontIndirectA (&mylogfont);
814 SendMessageA (infoPtr->hwndCombo, WM_SETFONT, (WPARAM)infoPtr->font, 0);
815 if (infoPtr->hwndEdit) {
816 SendMessageA (infoPtr->hwndEdit, WM_SETFONT, (WPARAM)infoPtr->font, 0);
817 SendMessageA (infoPtr->hwndEdit, EM_SETMARGINS, (WPARAM)EC_USEFONTINFO, 0);
820 COMBOEX_ReSize (hwnd, infoPtr);
822 /* Above is fairly certain, below is much less certain. */
824 GetWindowRect(hwnd, &wnrc1);
825 GetClientRect(hwnd, &clrc1);
826 GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
827 TRACE("Ex wnd=(%d,%d)-(%d,%d) Ex clt=(%d,%d)-(%d,%d) Cb wnd=(%d,%d)-(%d,%d)\n",
828 wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom,
829 clrc1.left, clrc1.top, clrc1.right, clrc1.bottom,
830 cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom);
831 SetWindowPos(infoPtr->hwndCombo, HWND_TOP,
832 0, 0, wnrc1.right-wnrc1.left, wnrc1.bottom-wnrc1.top,
833 SWP_NOACTIVATE | SWP_NOREDRAW);
835 GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
836 TRACE("Ex wnd=(%d,%d)-(%d,%d)\n",
837 cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom);
838 SetWindowPos(hwnd, HWND_TOP,
839 0, 0, cmbwrc.right-cmbwrc.left, cmbwrc.bottom-cmbwrc.top,
840 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
842 COMBOEX_AdjustEditPos (infoPtr);
845 * Create an item structure to represent the data in the
846 * EDIT control.
848 item = (CBE_ITEMDATA *)COMCTL32_Alloc (sizeof (CBE_ITEMDATA));
849 item->next = NULL;
850 item->pszText = NULL;
851 item->mask = 0;
852 infoPtr->edit = item;
854 return 0;
858 inline static LRESULT
859 COMBOEX_DrawItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
861 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
862 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
863 CBE_ITEMDATA *item = 0;
864 SIZE txtsize;
865 RECT rect;
866 int drawimage;
867 UINT xbase;
868 UINT xioff = 0; /* size and spacer of image if any */
869 IMAGEINFO iinfo;
870 INT len;
872 if (!IsWindowEnabled(infoPtr->hwndCombo)) return 0;
874 /* MSDN says: */
875 /* "itemID - Specifies the menu item identifier for a menu */
876 /* item or the index of the item in a list box or combo box. */
877 /* For an empty list box or combo box, this member can be -1. */
878 /* This allows the application to draw only the focus */
879 /* rectangle at the coordinates specified by the rcItem */
880 /* member even though there are no items in the control. */
881 /* This indicates to the user whether the list box or combo */
882 /* box has the focus. How the bits are set in the itemAction */
883 /* member determines whether the rectangle is to be drawn as */
884 /* though the list box or combo box has the focus. */
885 if (dis->itemID == 0xffffffff) {
886 if ( ( (dis->itemAction & ODA_FOCUS) && (dis->itemState & ODS_SELECTED)) ||
887 ( (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) && (dis->itemState & ODS_FOCUS) ) ) {
888 TRACE("drawing item -1 special focus, rect=(%d,%d)-(%d,%d)\n",
889 dis->rcItem.left, dis->rcItem.top,
890 dis->rcItem.right, dis->rcItem.bottom);
891 DrawFocusRect(dis->hDC, &dis->rcItem);
892 return 0;
894 else if ((dis->CtlType == ODT_COMBOBOX) &&
895 (dis->itemAction == ODA_DRAWENTIRE) &&
896 (dis->itemState == 0)) {
897 /* draw of edit control data */
898 CHAR str[260];
899 INT wlen, alen;
901 TRACE("drawing edit control\n");
902 item = infoPtr->edit;
904 if (item->pszText) {
905 COMCTL32_Free(item->pszText);
906 item->pszText = 0;
907 item->mask &= ~CBEIF_TEXT;
909 if (infoPtr->hwndEdit) {
910 alen = SendMessageA (infoPtr->hwndEdit, WM_GETTEXT, 260, (LPARAM)&str);
911 TRACE("hwndEdit=%0x, text len=%d str=<%s>\n", infoPtr->hwndEdit, alen, str);
912 if (alen > 0) {
913 item->mask |= CBEIF_TEXT;
914 wlen = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
915 if (wlen > 0) {
916 item->pszText = (LPWSTR)COMCTL32_Alloc ((wlen + 1)*sizeof(WCHAR));
917 MultiByteToWideChar (CP_ACP, 0, str, -1, item->pszText, wlen);
923 /* testing */
925 RECT exrc, cbrc, edrc;
926 GetWindowRect (hwnd, &exrc);
927 GetWindowRect (infoPtr->hwndCombo, &cbrc);
928 edrc.left=edrc.top=edrc.right=edrc.bottom=-1;
929 if (infoPtr->hwndEdit)
930 GetWindowRect (infoPtr->hwndEdit, &edrc);
931 TRACE("window rects ex=(%d,%d)-(%d,%d), cb=(%d,%d)-(%d,%d), ed=(%d,%d)-(%d,%d)\n",
932 exrc.left, exrc.top, exrc.right, exrc.bottom,
933 cbrc.left, cbrc.top, cbrc.right, cbrc.bottom,
934 edrc.left, edrc.top, edrc.right, edrc.bottom);
937 else {
938 ERR("NOT drawing item -1 special focus, rect=(%d,%d)-(%d,%d), action=%08x, state=%08x\n",
939 dis->rcItem.left, dis->rcItem.top,
940 dis->rcItem.right, dis->rcItem.bottom,
941 dis->itemAction, dis->itemState);
942 return 0;
946 if (!item)
947 item = (CBE_ITEMDATA *)SendMessageA (infoPtr->hwndCombo,
948 CB_GETITEMDATA, (WPARAM)dis->itemID, 0);
949 if (item == (CBE_ITEMDATA *)CB_ERR)
951 FIXME("invalid item for id %d \n",dis->itemID);
952 return 0;
954 if (!TRACE_ON(message)) {
955 TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n",
956 dis->CtlType, dis->CtlID);
957 TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n",
958 dis->itemID, dis->itemAction, dis->itemState);
959 TRACE("hWnd=0x%04x hDC=0x%04x (%d,%d)-(%d,%d) itemData=0x%08lx\n",
960 dis->hwndItem, dis->hDC, dis->rcItem.left,
961 dis->rcItem.top, dis->rcItem.right, dis->rcItem.bottom,
962 dis->itemData);
964 COMBOEX_DumpItem (item);
966 xbase = CBE_STARTOFFSET;
967 if (item->mask & CBEIF_INDENT)
968 xbase += (item->iIndent * CBE_INDENT);
969 if (item->mask & CBEIF_IMAGE) {
970 ImageList_GetImageInfo(infoPtr->himl, item->iImage, &iinfo);
971 xioff = (iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP);
974 switch (dis->itemAction) {
975 case ODA_FOCUS:
976 if (dis->itemState & ODS_SELECTED /*1*/) {
977 if ((item->mask & CBEIF_TEXT) && item->pszText) {
978 len = strlenW (item->pszText);
979 GetTextExtentPointW (dis->hDC, item->pszText, len, &txtsize);
980 rect.left = xbase + xioff - 1;
981 rect.top = dis->rcItem.top - 1 +
982 (dis->rcItem.bottom - dis->rcItem.top - txtsize.cy) / 2;
983 rect.right = rect.left + txtsize.cx + 2;
984 rect.bottom = rect.top + txtsize.cy + 2;
985 TRACE("drawing item %d focus, rect=(%d,%d)-(%d,%d)\n",
986 dis->itemID, rect.left, rect.top,
987 rect.right, rect.bottom);
988 DrawFocusRect(dis->hDC, &rect);
991 break;
992 case ODA_SELECT:
993 case ODA_DRAWENTIRE:
994 drawimage = -1;
995 if (item->mask & CBEIF_IMAGE) drawimage = item->iImage;
996 if ((dis->itemState & ODS_SELECTED) &&
997 (item->mask & CBEIF_SELECTEDIMAGE))
998 drawimage = item->iSelectedImage;
999 if (drawimage != -1) {
1000 ImageList_Draw (infoPtr->himl, drawimage, dis->hDC,
1001 xbase, dis->rcItem.top,
1002 (dis->itemState & ODS_SELECTED) ?
1003 ILD_SELECTED : ILD_NORMAL);
1005 if ((item->mask & CBEIF_TEXT) && item->pszText) {
1006 UINT x, y;
1007 COLORREF nbkc, ntxc;
1009 len = strlenW (item->pszText);
1010 GetTextExtentPointW (dis->hDC, item->pszText, len, &txtsize);
1011 nbkc = GetSysColor ((dis->itemState & ODS_SELECTED) ?
1012 COLOR_HIGHLIGHT : COLOR_WINDOW);
1013 SetBkColor (dis->hDC, nbkc);
1014 ntxc = GetSysColor ((dis->itemState & ODS_SELECTED) ?
1015 COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT);
1016 SetTextColor (dis->hDC, ntxc);
1017 x = xbase + xioff;
1018 y = dis->rcItem.top +
1019 (dis->rcItem.bottom - dis->rcItem.top - txtsize.cy) / 2;
1020 rect.left = x;
1021 rect.right = x + txtsize.cx;
1022 rect.top = y;
1023 rect.bottom = y + txtsize.cy;
1024 TRACE("drawing item %d text, rect=(%d,%d)-(%d,%d)\n",
1025 dis->itemID, rect.left, rect.top, rect.right, rect.bottom);
1026 ExtTextOutW (dis->hDC, x, y, ETO_OPAQUE | ETO_CLIPPED,
1027 &rect, item->pszText, len, 0);
1028 if (dis->itemState & ODS_FOCUS) {
1029 rect.top -= 1;
1030 rect.bottom += 1;
1031 rect.left -= 1;
1032 rect.right += 2;
1033 TRACE("drawing item %d focus, rect=(%d,%d)-(%d,%d)\n",
1034 dis->itemID, rect.left, rect.top, rect.right, rect.bottom);
1035 DrawFocusRect (dis->hDC, &rect);
1038 break;
1039 default:
1040 FIXME("unknown action hwnd=%08x, wparam=%08x, lparam=%08lx, action=%d\n",
1041 hwnd, wParam, lParam, dis->itemAction);
1044 return 0;
1048 static LRESULT
1049 COMBOEX_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1051 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1053 if (infoPtr->hwndCombo)
1054 DestroyWindow (infoPtr->hwndCombo);
1056 if (infoPtr->edit) {
1057 COMCTL32_Free (infoPtr->edit);
1058 infoPtr->edit = 0;
1061 if (infoPtr->items) {
1062 CBE_ITEMDATA *this, *next;
1064 this = infoPtr->items;
1065 while (this) {
1066 next = (CBE_ITEMDATA *)this->next;
1067 if ((this->mask & CBEIF_TEXT) && this->pszText)
1068 COMCTL32_Free (this->pszText);
1069 COMCTL32_Free (this);
1070 this = next;
1074 DeleteObject (infoPtr->font);
1076 /* free comboex info data */
1077 COMCTL32_Free (infoPtr);
1078 SetWindowLongA (hwnd, 0, 0);
1079 return 0;
1083 static LRESULT
1084 COMBOEX_MeasureItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1086 /*COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);*/
1087 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *) lParam;
1088 HDC hdc;
1089 SIZE mysize;
1091 hdc = GetDC (0);
1092 GetTextExtentPointA (hdc, "W", 1, &mysize);
1093 ReleaseDC (0, hdc);
1094 mis->itemHeight = mysize.cy + CBE_EXTRA;
1096 TRACE("adjusted height hwnd=%08x, height=%d\n",
1097 hwnd, mis->itemHeight);
1099 return 0;
1103 static LRESULT
1104 COMBOEX_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1106 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1107 RECT rect;
1109 GetWindowRect (hwnd, &rect);
1110 TRACE("my rect (%d,%d)-(%d,%d)\n",
1111 rect.left, rect.top, rect.right, rect.bottom);
1113 MoveWindow (infoPtr->hwndCombo, 0, 0, rect.right -rect.left,
1114 rect.bottom - rect.top, TRUE);
1116 COMBOEX_AdjustEditPos (infoPtr);
1118 return 0;
1122 static LRESULT
1123 COMBOEX_WindowPosChanging (HWND hwnd, WPARAM wParam, LPARAM lParam)
1125 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
1126 LRESULT ret;
1127 RECT cbx_wrect, cbx_crect, cb_wrect;
1128 UINT width;
1129 WINDOWPOS *wp = (WINDOWPOS *)lParam;
1131 ret = DefWindowProcA (hwnd, WM_WINDOWPOSCHANGING, wParam, lParam);
1132 GetWindowRect (hwnd, &cbx_wrect);
1133 GetClientRect (hwnd, &cbx_crect);
1134 GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
1136 /* width is winpos value + border width of comboex */
1137 width = wp->cx
1138 + cbx_wrect.right-cbx_wrect.left
1139 - (cbx_crect.right - cbx_crect.left);
1141 TRACE("EX window=(%d,%d)-(%d,%d), client=(%d,%d)-(%d,%d)\n",
1142 cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom,
1143 cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom);
1144 TRACE("CB window=(%d,%d)-(%d,%d), EX setting=(0,0)-(%d,%d)\n",
1145 cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom,
1146 width, cb_wrect.bottom-cb_wrect.top);
1148 SetWindowPos (infoPtr->hwndCombo, HWND_TOP, 0, 0,
1149 width,
1150 cb_wrect.bottom-cb_wrect.top,
1151 SWP_NOACTIVATE);
1153 /* ****** new # 3 ******* */
1154 COMBOEX_AdjustEditPos (infoPtr);
1156 return 0;
1160 static LRESULT WINAPI
1161 COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1163 COMBOEX_INFO *infoPtr = (COMBOEX_INFO *)GetPropA (hwnd, (LPCSTR)(LONG) ComboExInfo);
1165 TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx, info_ptr=%p\n",
1166 hwnd, uMsg, wParam, lParam, infoPtr);
1168 if (!infoPtr) return 0;
1170 switch (uMsg)
1173 case WM_KEYDOWN: {
1174 NMCBEENDEDITA cbeend;
1175 INT oldItem;
1176 CBE_ITEMDATA *item;
1178 switch ((INT)wParam)
1180 case VK_ESCAPE:
1181 /* native version seems to do following for COMBOEX */
1183 * GetWindowTextA(Edit,&?, 0x104) x
1184 * CB_GETCURSEL to Combo rets -1 x
1185 * WM_NOTIFY to COMBOEX parent (rebar) x
1186 * (CBEN_ENDEDIT{A|W}
1187 * fChanged = FALSE x
1188 * inewSelection = -1 x
1189 * txt="www.hoho" x
1190 * iWhy = 3 x
1191 * CB_GETCURSEL to Combo rets -1 x
1192 * InvalidateRect(Combo, 0) x
1193 * WM_SETTEXT to Edit x
1194 * EM_SETSEL to Edit (0,0) x
1195 * EM_SETSEL to Edit (0,-1) x
1196 * RedrawWindow(Combo, 0, 0, 5) x
1198 TRACE("special code for VK_ESCAPE\n");
1200 GetWindowTextA (infoPtr->hwndEdit, cbeend.szText, 260);
1202 infoPtr->flags &= ~WCBE_ACTEDIT;
1203 cbeend.fChanged = FALSE;
1204 cbeend.iNewSelection = SendMessageA (infoPtr->hwndCombo,
1205 CB_GETCURSEL, 0, 0);
1206 cbeend.iWhy = CBENF_ESCAPE;
1208 if (COMBOEX_Notify (infoPtr, CBEN_ENDEDITA,
1209 (NMHDR *)&cbeend)) {
1210 /* abort the change */
1211 return 0;
1213 oldItem = SendMessageA (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0);
1214 InvalidateRect (infoPtr->hwndCombo, 0, 0);
1215 if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) {
1216 ERR("item %d not found. Problem!\n", oldItem);
1217 break;
1220 COMBOEX_SetEditText (infoPtr, item);
1221 RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE |
1222 RDW_INVALIDATE);
1223 break;
1225 case VK_RETURN:
1226 /* native version seems to do following for COMBOEX */
1228 * GetWindowTextA(Edit,&?, 0x104) x
1229 * CB_GETCURSEL to Combo rets -1 x
1230 * CB_GETCOUNT to Combo rets 0
1231 * WM_NOTIFY to COMBOEX parent (rebar) x
1232 * (CBEN_ENDEDIT{A|W}
1233 * fChanged = TRUE (-1) x
1234 * iNewSelection = -1 x
1235 * txt= x
1236 * iWhy = 2 (CBENF_RETURN) x
1237 * CB_GETCURSEL to Combo rets -1 x
1238 * InvalidateRect(Combo, 0, 0) x
1239 * SetFocus(Edit) x
1240 * CallWindowProc(406615a8, Edit, 0x100, 0xd, 0x1c0001)
1243 TRACE("special code for VK_RETURN\n");
1245 GetWindowTextA (infoPtr->hwndEdit, cbeend.szText, 260);
1247 infoPtr->flags &= ~WCBE_ACTEDIT;
1248 cbeend.iNewSelection = SendMessageA (infoPtr->hwndCombo,
1249 CB_GETCURSEL, 0, 0);
1250 cbeend.fChanged = TRUE;
1251 cbeend.iWhy = CBENF_RETURN;
1253 if (COMBOEX_Notify (infoPtr, CBEN_ENDEDITA,
1254 (NMHDR *)&cbeend)) {
1255 /* abort the change */
1256 return 0;
1258 oldItem = SendMessageA (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0);
1259 InvalidateRect (infoPtr->hwndCombo, 0, 0);
1260 SetFocus(infoPtr->hwndEdit);
1261 break;
1263 default:
1264 return CallWindowProcA (infoPtr->prevEditWndProc,
1265 hwnd, uMsg, wParam, lParam);
1267 return 0;
1269 case WM_KILLFOCUS:
1271 * should do NOTIFY CBEN_ENDEDIT with CBENF_KILLFOCUS
1272 * ** fall through for now **
1274 infoPtr->flags &= ~WCBE_ACTEDIT;
1276 case WM_CHAR:
1277 case WM_ERASEBKGND:
1278 /* The above messages need code - will be delivered later */
1279 default:
1280 return CallWindowProcA (infoPtr->prevEditWndProc,
1281 hwnd, uMsg, wParam, lParam);
1283 return 0;
1287 static LRESULT WINAPI
1288 COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1290 COMBOEX_INFO *infoPtr = (COMBOEX_INFO *)GetPropA (hwnd, (LPCSTR)(LONG) ComboExInfo);
1292 TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx, info_ptr=%p\n",
1293 hwnd, uMsg, wParam, lParam, infoPtr);
1295 if (!infoPtr) return 0;
1297 switch (uMsg)
1299 case WM_COMMAND:
1300 /* traces show that COMBOEX does not issue CBN_EDITUPDATE
1301 * on the EN_UPDATE
1303 if (HIWORD(wParam) == EN_UPDATE) return 0;
1305 if (HIWORD(wParam) == EN_SETFOCUS) {
1307 * For EN_SETFOCUS this issues the same calls and messages
1308 * as the native seems to do.
1310 NMHDR hdr;
1312 SendMessageA (infoPtr->hwndEdit, EM_SETSEL, 0, 0);
1313 SendMessageA (infoPtr->hwndEdit, EM_SETSEL, 0, -1);
1314 COMBOEX_Notify (infoPtr, CBEN_BEGINEDIT, &hdr);
1315 infoPtr->flags |= WCBE_ACTEDIT;
1316 return 0;
1319 if (HIWORD(wParam) == EN_CHANGE) {
1321 * For EN_CHANGE this issues the same calls and messages
1322 * as the native seems to do.
1324 WCHAR selected_text[260];
1325 INT selected, cnt;
1326 CBE_ITEMDATA *item;
1328 selected = SendMessageA (infoPtr->hwndCombo,
1329 CB_GETCURSEL, 0, 0);
1331 /* lstrlenA( lastworkingURL ) */
1333 if (selected == -1)
1334 GetWindowTextW (infoPtr->hwndEdit, selected_text, 260);
1335 else {
1336 item = COMBOEX_FindItem (infoPtr, selected);
1337 cnt = lstrlenW (item->pszText);
1338 if (cnt >= 259) cnt = 259;
1339 lstrcpynW (selected_text, item->pszText, cnt);
1340 selected_text[cnt+1] = 0;
1343 TRACE("handling EN_CHANGE, selected = %d, text=%s\n",
1344 selected, debugstr_w(selected_text));
1346 /* lstrcmpiW is between lastworkingURL and GetWindowText */
1348 if (lstrcmpiW (infoPtr->edit->pszText, selected_text)) {
1349 /* strings not equal -- what to do???? */
1350 ERR("strings do not match\n");
1352 SendMessageA ( GetParent(infoPtr->hwndSelf), WM_COMMAND,
1353 MAKEWPARAM(GetDlgCtrlID (infoPtr->hwndSelf),
1354 CBN_EDITCHANGE),
1355 infoPtr->hwndSelf);
1356 return 0;
1359 /* fall through */
1361 case WM_ERASEBKGND:
1362 case WM_SETCURSOR:
1363 /* The above messages need code - will be delivered later */
1364 default:
1365 return CallWindowProcA (infoPtr->prevComboWndProc,
1366 hwnd, uMsg, wParam, lParam);
1368 return 0;
1372 static LRESULT WINAPI
1373 COMBOEX_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1375 TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
1376 if (!COMBOEX_GetInfoPtr (hwnd) && (uMsg != WM_CREATE))
1377 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1379 switch (uMsg)
1381 /* case CBEM_DELETEITEM: */
1383 case CBEM_GETCOMBOCONTROL:
1384 return COMBOEX_GetComboControl (hwnd, wParam, lParam);
1386 case CBEM_GETEDITCONTROL:
1387 return COMBOEX_GetEditControl (hwnd, wParam, lParam);
1389 case CBEM_GETEXTENDEDSTYLE:
1390 return COMBOEX_GetExtendedStyle (hwnd, wParam, lParam);
1392 case CBEM_GETIMAGELIST:
1393 return COMBOEX_GetImageList (hwnd, wParam, lParam);
1395 /* case CBEM_GETITEMA:
1396 case CBEM_GETITEMW:
1397 case CBEM_GETUNICODEFORMAT:
1400 case CBEM_HASEDITCHANGED:
1401 return COMBOEX_HasEditChanged (hwnd, wParam, lParam);
1403 case CBEM_INSERTITEMA:
1404 return COMBOEX_InsertItemA (hwnd, wParam, lParam);
1406 case CBEM_INSERTITEMW:
1407 return COMBOEX_InsertItemW (hwnd, wParam, lParam);
1409 case CBEM_SETEXSTYLE: /* FIXME: obsoleted, should be the same as: */
1410 case CBEM_SETEXTENDEDSTYLE:
1411 return COMBOEX_SetExtendedStyle (hwnd, wParam, lParam);
1413 case CBEM_SETIMAGELIST:
1414 return COMBOEX_SetImageList (hwnd, wParam, lParam);
1416 case CBEM_SETITEMA:
1417 return COMBOEX_SetItemA (hwnd, wParam, lParam);
1419 case CBEM_SETITEMW:
1420 return COMBOEX_SetItemW (hwnd, wParam, lParam);
1422 /* case CBEM_SETUNICODEFORMAT:
1425 case CB_DELETESTRING:
1426 case CB_FINDSTRINGEXACT:
1427 case CB_GETCOUNT:
1428 case CB_GETCURSEL:
1429 case CB_GETDROPPEDCONTROLRECT:
1430 case CB_GETDROPPEDSTATE:
1431 case CB_GETITEMDATA:
1432 case CB_GETITEMHEIGHT:
1433 case CB_GETLBTEXT:
1434 case CB_GETLBTEXTLEN:
1435 case CB_GETEXTENDEDUI:
1436 case CB_LIMITTEXT:
1437 case CB_RESETCONTENT:
1438 case CB_SELECTSTRING:
1439 case CB_SETDROPPEDWIDTH: /* used by IE 4 */
1440 case CB_SETEXTENDEDUI: /* used by IE 4 */
1441 case CB_SETITEMDATA:
1442 case CB_SHOWDROPDOWN: /* used by IE 4 */
1443 case WM_SETTEXT:
1444 case WM_GETTEXT:
1445 return COMBOEX_Forward (hwnd, uMsg, wParam, lParam);
1447 case CB_SETCURSEL:
1448 return COMBOEX_SetCursel (hwnd, wParam, lParam);
1450 case CB_SETITEMHEIGHT:
1451 return COMBOEX_SetItemHeight (hwnd, wParam, lParam);
1454 /* Messages passed to parent */
1455 case WM_COMMAND:
1456 case WM_NOTIFY:
1457 return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
1460 case WM_CREATE:
1461 return COMBOEX_Create (hwnd, wParam, lParam);
1463 case WM_DRAWITEM:
1464 return COMBOEX_DrawItem (hwnd, wParam, lParam);
1466 case WM_DESTROY:
1467 return COMBOEX_Destroy (hwnd, wParam, lParam);
1469 case WM_MEASUREITEM:
1470 return COMBOEX_MeasureItem (hwnd, wParam, lParam);
1472 case WM_SIZE:
1473 return COMBOEX_Size (hwnd, wParam, lParam);
1475 case WM_WINDOWPOSCHANGING:
1476 return COMBOEX_WindowPosChanging (hwnd, wParam, lParam);
1478 default:
1479 if (uMsg >= WM_USER)
1480 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
1481 uMsg, wParam, lParam);
1482 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1484 return 0;
1488 VOID
1489 COMBOEX_Register (void)
1491 WNDCLASSA wndClass;
1493 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1494 wndClass.style = CS_GLOBALCLASS;
1495 wndClass.lpfnWndProc = (WNDPROC)COMBOEX_WindowProc;
1496 wndClass.cbClsExtra = 0;
1497 wndClass.cbWndExtra = sizeof(COMBOEX_INFO *);
1498 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
1499 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1500 wndClass.lpszClassName = WC_COMBOBOXEXA;
1502 RegisterClassA (&wndClass);
1504 ComboExInfo = GlobalAddAtomA("CC32SubclassInfo");
1508 VOID
1509 COMBOEX_Unregister (void)
1511 UnregisterClassA (WC_COMBOBOXEXA, (HINSTANCE)NULL);