Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencomboex.c
Go to the documentation of this file.
00001 /* 00002 * ComboBoxEx control 00003 * 00004 * Copyright 1998, 1999 Eric Kohl 00005 * Copyright 2000, 2001, 2002 Guy Albertelli <galberte@neo.lrun.com> 00006 * Copyright 2002 Dimitrie O. Paun 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00021 * 00022 * NOTE 00023 * 00024 * This code was audited for completeness against the documented features 00025 * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun. 00026 * 00027 * Unless otherwise noted, we believe this code to be complete, as per 00028 * the specification mentioned above. 00029 * If you discover missing features, or bugs, please note them below. 00030 * 00031 */ 00032 00033 #include <stdarg.h> 00034 #include <string.h> 00035 #include "windef.h" 00036 #include "winbase.h" 00037 #include "wingdi.h" 00038 #include "winuser.h" 00039 #include "winnls.h" 00040 #include "commctrl.h" 00041 #include "comctl32.h" 00042 #include "wine/debug.h" 00043 #include "wine/unicode.h" 00044 00045 WINE_DEFAULT_DEBUG_CHANNEL(comboex); 00046 00047 /* Item structure */ 00048 typedef struct _CBE_ITEMDATA 00049 { 00050 struct _CBE_ITEMDATA *next; 00051 UINT mask; 00052 LPWSTR pszText; 00053 LPWSTR pszTemp; 00054 int cchTextMax; 00055 int iImage; 00056 int iSelectedImage; 00057 int iOverlay; 00058 int iIndent; 00059 LPARAM lParam; 00060 } CBE_ITEMDATA; 00061 00062 /* ComboBoxEx structure */ 00063 typedef struct 00064 { 00065 HIMAGELIST himl; 00066 HWND hwndSelf; /* my own hwnd */ 00067 HWND hwndNotify; /* my parent hwnd */ 00068 HWND hwndCombo; 00069 HWND hwndEdit; 00070 DWORD dwExtStyle; 00071 INT selected; /* index of selected item */ 00072 DWORD flags; /* WINE internal flags */ 00073 HFONT defaultFont; 00074 HFONT font; 00075 INT nb_items; /* Number of items */ 00076 BOOL unicode; /* TRUE if this window is Unicode */ 00077 BOOL NtfUnicode; /* TRUE if parent wants notify in Unicode */ 00078 CBE_ITEMDATA *edit; /* item data for edit item */ 00079 CBE_ITEMDATA *items; /* Array of items */ 00080 } COMBOEX_INFO; 00081 00082 /* internal flags in the COMBOEX_INFO structure */ 00083 #define WCBE_ACTEDIT 0x00000001 /* Edit active i.e. 00084 * CBEN_BEGINEDIT issued 00085 * but CBEN_ENDEDIT{A|W} 00086 * not yet issued. */ 00087 #define WCBE_EDITCHG 0x00000002 /* Edit issued EN_CHANGE */ 00088 #define WCBE_EDITHASCHANGED (WCBE_ACTEDIT | WCBE_EDITCHG) 00089 #define WCBE_EDITFOCUSED 0x00000004 /* Edit control has focus */ 00090 #define WCBE_MOUSECAPTURED 0x00000008 /* Combo has captured mouse */ 00091 #define WCBE_MOUSEDRAGGED 0x00000010 /* User has dragged in combo */ 00092 00093 #define ID_CB_EDIT 1001 00094 00095 00096 /* 00097 * Special flag set in DRAWITEMSTRUCT itemState field. It is set by 00098 * the ComboEx version of the Combo Window Proc so that when the 00099 * WM_DRAWITEM message is then passed to ComboEx, we know that this 00100 * particular WM_DRAWITEM message is for listbox only items. Any message 00101 * without this flag is then for the Edit control field. 00102 * 00103 * We really cannot use the ODS_COMBOBOXEDIT flag because MSDN states that 00104 * only version 4.0 applications will have ODS_COMBOBOXEDIT set. 00105 */ 00106 #define ODS_COMBOEXLBOX 0x4000 00107 00108 00109 00110 /* Height in pixels of control over the amount of the selected font */ 00111 #define CBE_EXTRA 3 00112 00113 /* Indent amount per MS documentation */ 00114 #define CBE_INDENT 10 00115 00116 /* Offset in pixels from left side for start of image or text */ 00117 #define CBE_STARTOFFSET 6 00118 00119 /* Offset between image and text */ 00120 #define CBE_SEP 4 00121 00122 #define COMBO_SUBCLASSID 1 00123 #define EDIT_SUBCLASSID 2 00124 00125 #define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongPtrW (hwnd, 0)) 00126 00127 static LRESULT CALLBACK COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 00128 UINT_PTR uId, DWORD_PTR ref_data); 00129 static LRESULT CALLBACK COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 00130 UINT_PTR uId, DWORD_PTR ref_data); 00131 static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr); 00132 typedef INT (WINAPI *cmp_func_t)(LPCWSTR, LPCWSTR); 00133 00134 static inline BOOL is_textW(LPCWSTR str) 00135 { 00136 return str && str != LPSTR_TEXTCALLBACKW; 00137 } 00138 00139 static inline BOOL is_textA(LPCSTR str) 00140 { 00141 return str && str != LPSTR_TEXTCALLBACKA; 00142 } 00143 00144 static inline LPCSTR debugstr_txt(LPCWSTR str) 00145 { 00146 if (str == LPSTR_TEXTCALLBACKW) return "(callback)"; 00147 return debugstr_w(str); 00148 } 00149 00150 static void COMBOEX_DumpItem (CBE_ITEMDATA const *item) 00151 { 00152 TRACE("item %p - mask=%08x, pszText=%p, cchTM=%d, iImage=%d\n", 00153 item, item->mask, item->pszText, item->cchTextMax, item->iImage); 00154 TRACE("item %p - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n", 00155 item, item->iSelectedImage, item->iOverlay, item->iIndent, item->lParam); 00156 if (item->mask & CBEIF_TEXT) 00157 TRACE("item %p - pszText=%s\n", item, debugstr_txt(item->pszText)); 00158 } 00159 00160 00161 static void COMBOEX_DumpInput (COMBOBOXEXITEMW const *input) 00162 { 00163 TRACE("input - mask=%08x, iItem=%ld, pszText=%p, cchTM=%d, iImage=%d\n", 00164 input->mask, input->iItem, input->pszText, input->cchTextMax, 00165 input->iImage); 00166 if (input->mask & CBEIF_TEXT) 00167 TRACE("input - pszText=<%s>\n", debugstr_txt(input->pszText)); 00168 TRACE("input - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n", 00169 input->iSelectedImage, input->iOverlay, input->iIndent, input->lParam); 00170 } 00171 00172 00173 static inline CBE_ITEMDATA *get_item_data(const COMBOEX_INFO *infoPtr, INT index) 00174 { 00175 return (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, CB_GETITEMDATA, 00176 index, 0); 00177 } 00178 00179 static inline cmp_func_t get_cmp_func(COMBOEX_INFO const *infoPtr) 00180 { 00181 return infoPtr->dwExtStyle & CBES_EX_CASESENSITIVE ? lstrcmpW : lstrcmpiW; 00182 } 00183 00184 static INT COMBOEX_Notify (const COMBOEX_INFO *infoPtr, INT code, NMHDR *hdr) 00185 { 00186 hdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); 00187 hdr->hwndFrom = infoPtr->hwndSelf; 00188 hdr->code = code; 00189 if (infoPtr->NtfUnicode) 00190 return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)hdr); 00191 else 00192 return SendMessageA (infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)hdr); 00193 } 00194 00195 00196 static INT 00197 COMBOEX_NotifyItem (const COMBOEX_INFO *infoPtr, UINT code, NMCOMBOBOXEXW *hdr) 00198 { 00199 /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */ 00200 if (infoPtr->NtfUnicode) 00201 return COMBOEX_Notify (infoPtr, code, &hdr->hdr); 00202 else { 00203 LPWSTR wstr = hdr->ceItem.pszText; 00204 LPSTR astr = 0; 00205 INT ret, len = 0; 00206 00207 if ((hdr->ceItem.mask & CBEIF_TEXT) && is_textW(wstr)) { 00208 len = WideCharToMultiByte (CP_ACP, 0, wstr, -1, 0, 0, NULL, NULL); 00209 if (len > 0) { 00210 astr = Alloc ((len + 1)*sizeof(CHAR)); 00211 if (!astr) return 0; 00212 WideCharToMultiByte (CP_ACP, 0, wstr, -1, astr, len, 0, 0); 00213 hdr->ceItem.pszText = (LPWSTR)astr; 00214 } 00215 } 00216 00217 if (code == CBEN_ENDEDITW) code = CBEN_ENDEDITA; 00218 else if (code == CBEN_GETDISPINFOW) code = CBEN_GETDISPINFOA; 00219 else if (code == CBEN_DRAGBEGINW) code = CBEN_DRAGBEGINA; 00220 00221 ret = COMBOEX_Notify (infoPtr, code, (NMHDR *)hdr); 00222 00223 if (astr && hdr->ceItem.pszText == (LPWSTR)astr) 00224 hdr->ceItem.pszText = wstr; 00225 00226 Free(astr); 00227 00228 return ret; 00229 } 00230 } 00231 00232 00233 static INT COMBOEX_NotifyEndEdit (const COMBOEX_INFO *infoPtr, NMCBEENDEDITW *neew, LPCWSTR wstr) 00234 { 00235 /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */ 00236 if (infoPtr->NtfUnicode) { 00237 lstrcpynW(neew->szText, wstr, CBEMAXSTRLEN); 00238 return COMBOEX_Notify (infoPtr, CBEN_ENDEDITW, &neew->hdr); 00239 } else { 00240 NMCBEENDEDITA neea; 00241 00242 neea.hdr = neew->hdr; 00243 neea.fChanged = neew->fChanged; 00244 neea.iNewSelection = neew->iNewSelection; 00245 WideCharToMultiByte (CP_ACP, 0, wstr, -1, neea.szText, CBEMAXSTRLEN, 0, 0); 00246 neea.iWhy = neew->iWhy; 00247 00248 return COMBOEX_Notify (infoPtr, CBEN_ENDEDITA, &neea.hdr); 00249 } 00250 } 00251 00252 00253 static void COMBOEX_NotifyDragBegin(const COMBOEX_INFO *infoPtr, LPCWSTR wstr) 00254 { 00255 /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */ 00256 if (infoPtr->NtfUnicode) { 00257 NMCBEDRAGBEGINW ndbw; 00258 00259 ndbw.iItemid = -1; 00260 lstrcpynW(ndbw.szText, wstr, CBEMAXSTRLEN); 00261 COMBOEX_Notify (infoPtr, CBEN_DRAGBEGINW, &ndbw.hdr); 00262 } else { 00263 NMCBEDRAGBEGINA ndba; 00264 00265 ndba.iItemid = -1; 00266 WideCharToMultiByte (CP_ACP, 0, wstr, -1, ndba.szText, CBEMAXSTRLEN, 0, 0); 00267 00268 COMBOEX_Notify (infoPtr, CBEN_DRAGBEGINA, &ndba.hdr); 00269 } 00270 } 00271 00272 00273 static void COMBOEX_FreeText (CBE_ITEMDATA *item) 00274 { 00275 if (is_textW(item->pszText)) Free(item->pszText); 00276 item->pszText = 0; 00277 Free(item->pszTemp); 00278 item->pszTemp = 0; 00279 } 00280 00281 00282 static INT COMBOEX_GetIndex(COMBOEX_INFO const *infoPtr, CBE_ITEMDATA const *item) 00283 { 00284 CBE_ITEMDATA const *moving; 00285 INT index; 00286 00287 moving = infoPtr->items; 00288 index = infoPtr->nb_items - 1; 00289 00290 while (moving && (moving != item)) { 00291 moving = moving->next; 00292 index--; 00293 } 00294 if (!moving || (index < 0)) { 00295 ERR("COMBOBOXEX item structures broken. Please report!\n"); 00296 return -1; 00297 } 00298 return index; 00299 } 00300 00301 00302 static LPCWSTR COMBOEX_GetText(const COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) 00303 { 00304 NMCOMBOBOXEXW nmce; 00305 LPWSTR text, buf; 00306 INT len; 00307 00308 if (item->pszText != LPSTR_TEXTCALLBACKW) 00309 return item->pszText; 00310 00311 ZeroMemory(&nmce, sizeof(nmce)); 00312 nmce.ceItem.mask = CBEIF_TEXT; 00313 nmce.ceItem.lParam = item->lParam; 00314 nmce.ceItem.iItem = COMBOEX_GetIndex(infoPtr, item); 00315 COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); 00316 00317 if (is_textW(nmce.ceItem.pszText)) { 00318 len = MultiByteToWideChar (CP_ACP, 0, (LPSTR)nmce.ceItem.pszText, -1, NULL, 0); 00319 buf = Alloc ((len + 1)*sizeof(WCHAR)); 00320 if (buf) 00321 MultiByteToWideChar (CP_ACP, 0, (LPSTR)nmce.ceItem.pszText, -1, buf, len); 00322 if (nmce.ceItem.mask & CBEIF_DI_SETITEM) { 00323 COMBOEX_FreeText(item); 00324 item->pszText = buf; 00325 } else { 00326 Free(item->pszTemp); 00327 item->pszTemp = buf; 00328 } 00329 text = buf; 00330 } else 00331 text = nmce.ceItem.pszText; 00332 00333 if (nmce.ceItem.mask & CBEIF_DI_SETITEM) 00334 item->pszText = text; 00335 return text; 00336 } 00337 00338 00339 static void COMBOEX_GetComboFontSize (const COMBOEX_INFO *infoPtr, SIZE *size) 00340 { 00341 static const WCHAR strA[] = { 'A', 0 }; 00342 HFONT nfont, ofont; 00343 HDC mydc; 00344 00345 mydc = GetDC (0); /* why the entire screen???? */ 00346 nfont = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0); 00347 ofont = SelectObject (mydc, nfont); 00348 GetTextExtentPointW (mydc, strA, 1, size); 00349 SelectObject (mydc, ofont); 00350 ReleaseDC (0, mydc); 00351 TRACE("selected font hwnd=%p, height=%d\n", nfont, size->cy); 00352 } 00353 00354 00355 static void COMBOEX_CopyItem (const CBE_ITEMDATA *item, COMBOBOXEXITEMW *cit) 00356 { 00357 if (cit->mask & CBEIF_TEXT) { 00358 /* 00359 * when given a text buffer actually use that buffer 00360 */ 00361 if (cit->pszText) { 00362 if (is_textW(item->pszText)) 00363 lstrcpynW(cit->pszText, item->pszText, cit->cchTextMax); 00364 else 00365 cit->pszText[0] = 0; 00366 } else { 00367 cit->pszText = item->pszText; 00368 cit->cchTextMax = item->cchTextMax; 00369 } 00370 } 00371 if (cit->mask & CBEIF_IMAGE) 00372 cit->iImage = item->iImage; 00373 if (cit->mask & CBEIF_SELECTEDIMAGE) 00374 cit->iSelectedImage = item->iSelectedImage; 00375 if (cit->mask & CBEIF_OVERLAY) 00376 cit->iOverlay = item->iOverlay; 00377 if (cit->mask & CBEIF_INDENT) 00378 cit->iIndent = item->iIndent; 00379 if (cit->mask & CBEIF_LPARAM) 00380 cit->lParam = item->lParam; 00381 } 00382 00383 00384 static void COMBOEX_AdjustEditPos (const COMBOEX_INFO *infoPtr) 00385 { 00386 SIZE mysize; 00387 INT x, y, w, h, xioff; 00388 RECT rect; 00389 00390 if (!infoPtr->hwndEdit) return; 00391 00392 if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) { 00393 IMAGEINFO iinfo; 00394 iinfo.rcImage.left = iinfo.rcImage.right = 0; 00395 ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo); 00396 xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP; 00397 } else xioff = 0; 00398 00399 GetClientRect (infoPtr->hwndCombo, &rect); 00400 InflateRect (&rect, -2, -2); 00401 InvalidateRect (infoPtr->hwndCombo, &rect, TRUE); 00402 00403 /* reposition the Edit control based on whether icon exists */ 00404 COMBOEX_GetComboFontSize (infoPtr, &mysize); 00405 TRACE("Combo font x=%d, y=%d\n", mysize.cx, mysize.cy); 00406 x = xioff + CBE_STARTOFFSET + 1; 00407 w = rect.right-rect.left - x - GetSystemMetrics(SM_CXVSCROLL) - 1; 00408 h = mysize.cy + 1; 00409 y = rect.bottom - h - 1; 00410 00411 TRACE("Combo client (%s), setting Edit to (%d,%d)-(%d,%d)\n", 00412 wine_dbgstr_rect(&rect), x, y, x + w, y + h); 00413 SetWindowPos(infoPtr->hwndEdit, HWND_TOP, x, y, w, h, 00414 SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER); 00415 } 00416 00417 00418 static void COMBOEX_ReSize (const COMBOEX_INFO *infoPtr) 00419 { 00420 SIZE mysize; 00421 LONG cy; 00422 IMAGEINFO iinfo; 00423 00424 COMBOEX_GetComboFontSize (infoPtr, &mysize); 00425 cy = mysize.cy + CBE_EXTRA; 00426 if (infoPtr->himl && ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo)) { 00427 cy = max (iinfo.rcImage.bottom - iinfo.rcImage.top, cy); 00428 TRACE("upgraded height due to image: height=%d\n", cy); 00429 } 00430 SendMessageW (infoPtr->hwndSelf, CB_SETITEMHEIGHT, -1, cy); 00431 if (infoPtr->hwndCombo) { 00432 SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT, 0, cy); 00433 if ( !(infoPtr->flags & CBES_EX_NOSIZELIMIT)) { 00434 RECT comboRect, ourRect; 00435 GetWindowRect(infoPtr->hwndCombo, &comboRect); 00436 GetWindowRect(infoPtr->hwndSelf, &ourRect); 00437 if (comboRect.bottom > ourRect.bottom) 00438 SetWindowPos( infoPtr->hwndSelf, 0, 0, 0, ourRect.right - ourRect.left, 00439 comboRect.bottom - comboRect.top, 00440 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW ); 00441 } 00442 } 00443 } 00444 00445 00446 static void COMBOEX_SetEditText (const COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) 00447 { 00448 if (!infoPtr->hwndEdit) return; 00449 00450 if (item->mask & CBEIF_TEXT) { 00451 SendMessageW (infoPtr->hwndEdit, WM_SETTEXT, 0, (LPARAM)COMBOEX_GetText(infoPtr, item)); 00452 SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0); 00453 SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1); 00454 } 00455 } 00456 00457 00458 static CBE_ITEMDATA * COMBOEX_FindItem(const COMBOEX_INFO *infoPtr, INT_PTR index) 00459 { 00460 CBE_ITEMDATA *item; 00461 INT i; 00462 00463 if ((index >= infoPtr->nb_items) || (index < -1)) 00464 return 0; 00465 if (index == -1) 00466 return infoPtr->edit; 00467 item = infoPtr->items; 00468 i = infoPtr->nb_items - 1; 00469 00470 /* find the item in the list */ 00471 while (item && (i > index)) { 00472 item = item->next; 00473 i--; 00474 } 00475 if (!item || (i != index)) { 00476 ERR("COMBOBOXEX item structures broken. Please report!\n"); 00477 return 0; 00478 } 00479 return item; 00480 } 00481 00482 /* *** CBEM_xxx message support *** */ 00483 00484 static UINT COMBOEX_GetListboxText(const COMBOEX_INFO *infoPtr, INT_PTR n, LPWSTR buf) 00485 { 00486 CBE_ITEMDATA *item; 00487 LPCWSTR str; 00488 00489 item = COMBOEX_FindItem(infoPtr, n); 00490 if (!item) 00491 return 0; 00492 00493 str = COMBOEX_GetText(infoPtr, item); 00494 if (!str) 00495 { 00496 if (buf) 00497 { 00498 if (infoPtr->unicode) 00499 buf[0] = 0; 00500 else 00501 *((LPSTR)buf) = 0; 00502 } 00503 return 0; 00504 } 00505 00506 if (infoPtr->unicode) 00507 { 00508 if (buf) 00509 lstrcpyW(buf, str); 00510 return lstrlenW(str); 00511 } 00512 else 00513 { 00514 UINT r; 00515 r = WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)buf, 0x40000000, NULL, NULL); 00516 if (r) r--; 00517 return r; 00518 } 00519 } 00520 00521 00522 static INT COMBOEX_DeleteItem (const COMBOEX_INFO *infoPtr, INT_PTR index) 00523 { 00524 TRACE("(index=%ld)\n", index); 00525 00526 /* if item number requested does not exist then return failure */ 00527 if ((index >= infoPtr->nb_items) || (index < 0)) return CB_ERR; 00528 if (!COMBOEX_FindItem(infoPtr, index)) return CB_ERR; 00529 00530 /* doing this will result in WM_DELETEITEM being issued */ 00531 SendMessageW (infoPtr->hwndCombo, CB_DELETESTRING, index, 0); 00532 00533 return infoPtr->nb_items; 00534 } 00535 00536 00537 static BOOL COMBOEX_GetItemW (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit) 00538 { 00539 INT_PTR index = cit->iItem; 00540 CBE_ITEMDATA *item; 00541 00542 TRACE("\n"); 00543 00544 /* if item number requested does not exist then return failure */ 00545 if ((index >= infoPtr->nb_items) || (index < -1)) return FALSE; 00546 00547 /* if the item is the edit control and there is no edit control, skip */ 00548 if ((index == -1) && !infoPtr->hwndEdit) return FALSE; 00549 00550 if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE; 00551 00552 COMBOEX_CopyItem (item, cit); 00553 00554 return TRUE; 00555 } 00556 00557 00558 static BOOL COMBOEX_GetItemA (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit) 00559 { 00560 COMBOBOXEXITEMW tmpcit; 00561 00562 TRACE("\n"); 00563 00564 tmpcit.mask = cit->mask; 00565 tmpcit.iItem = cit->iItem; 00566 tmpcit.pszText = 0; 00567 if(!COMBOEX_GetItemW (infoPtr, &tmpcit)) return FALSE; 00568 00569 if (cit->mask & CBEIF_TEXT) 00570 { 00571 if (is_textW(tmpcit.pszText) && cit->pszText) 00572 WideCharToMultiByte(CP_ACP, 0, tmpcit.pszText, -1, 00573 cit->pszText, cit->cchTextMax, NULL, NULL); 00574 else if (cit->pszText) cit->pszText[0] = 0; 00575 else cit->pszText = (LPSTR)tmpcit.pszText; 00576 } 00577 00578 if (cit->mask & CBEIF_IMAGE) 00579 cit->iImage = tmpcit.iImage; 00580 if (cit->mask & CBEIF_SELECTEDIMAGE) 00581 cit->iSelectedImage = tmpcit.iSelectedImage; 00582 if (cit->mask & CBEIF_OVERLAY) 00583 cit->iOverlay = tmpcit.iOverlay; 00584 if (cit->mask & CBEIF_INDENT) 00585 cit->iIndent = tmpcit.iIndent; 00586 if (cit->mask & CBEIF_LPARAM) 00587 cit->lParam = tmpcit.lParam; 00588 00589 return TRUE; 00590 } 00591 00592 00593 static inline BOOL COMBOEX_HasEditChanged (COMBOEX_INFO const *infoPtr) 00594 { 00595 return infoPtr->hwndEdit && (infoPtr->flags & WCBE_EDITHASCHANGED) == WCBE_EDITHASCHANGED; 00596 } 00597 00598 00599 static INT COMBOEX_InsertItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW const *cit) 00600 { 00601 INT_PTR index; 00602 CBE_ITEMDATA *item; 00603 NMCOMBOBOXEXW nmcit; 00604 00605 TRACE("\n"); 00606 00607 if (TRACE_ON(comboex)) COMBOEX_DumpInput (cit); 00608 00609 /* get real index of item to insert */ 00610 index = cit->iItem; 00611 if (index == -1) index = infoPtr->nb_items; 00612 if (index > infoPtr->nb_items) return -1; 00613 00614 /* get zero-filled space and chain it in */ 00615 if(!(item = Alloc (sizeof(*item)))) return -1; 00616 00617 /* locate position to insert new item in */ 00618 if (index == infoPtr->nb_items) { 00619 /* fast path for iItem = -1 */ 00620 item->next = infoPtr->items; 00621 infoPtr->items = item; 00622 } 00623 else { 00624 INT i = infoPtr->nb_items-1; 00625 CBE_ITEMDATA *moving = infoPtr->items; 00626 00627 while ((i > index) && moving) { 00628 moving = moving->next; 00629 i--; 00630 } 00631 if (!moving) { 00632 ERR("COMBOBOXEX item structures broken. Please report!\n"); 00633 Free(item); 00634 return -1; 00635 } 00636 item->next = moving->next; 00637 moving->next = item; 00638 } 00639 00640 /* fill in our hidden item structure */ 00641 item->mask = cit->mask; 00642 if (item->mask & CBEIF_TEXT) { 00643 INT len = 0; 00644 00645 if (is_textW(cit->pszText)) len = strlenW (cit->pszText); 00646 if (len > 0) { 00647 item->pszText = Alloc ((len + 1)*sizeof(WCHAR)); 00648 if (!item->pszText) { 00649 Free(item); 00650 return -1; 00651 } 00652 strcpyW (item->pszText, cit->pszText); 00653 } 00654 else if (cit->pszText == LPSTR_TEXTCALLBACKW) 00655 item->pszText = LPSTR_TEXTCALLBACKW; 00656 item->cchTextMax = cit->cchTextMax; 00657 } 00658 if (item->mask & CBEIF_IMAGE) 00659 item->iImage = cit->iImage; 00660 if (item->mask & CBEIF_SELECTEDIMAGE) 00661 item->iSelectedImage = cit->iSelectedImage; 00662 if (item->mask & CBEIF_OVERLAY) 00663 item->iOverlay = cit->iOverlay; 00664 if (item->mask & CBEIF_INDENT) 00665 item->iIndent = cit->iIndent; 00666 if (item->mask & CBEIF_LPARAM) 00667 item->lParam = cit->lParam; 00668 infoPtr->nb_items++; 00669 00670 if (TRACE_ON(comboex)) COMBOEX_DumpItem (item); 00671 00672 SendMessageW (infoPtr->hwndCombo, CB_INSERTSTRING, cit->iItem, (LPARAM)item); 00673 00674 memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem)); 00675 nmcit.ceItem.mask=~0; 00676 COMBOEX_CopyItem (item, &nmcit.ceItem); 00677 COMBOEX_NotifyItem (infoPtr, CBEN_INSERTITEM, &nmcit); 00678 00679 return index; 00680 00681 } 00682 00683 00684 static INT COMBOEX_InsertItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA const *cit) 00685 { 00686 COMBOBOXEXITEMW citW; 00687 LPWSTR wstr = NULL; 00688 INT ret; 00689 00690 memcpy(&citW,cit,sizeof(COMBOBOXEXITEMA)); 00691 if (cit->mask & CBEIF_TEXT && is_textA(cit->pszText)) { 00692 INT len = MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, NULL, 0); 00693 wstr = Alloc ((len + 1)*sizeof(WCHAR)); 00694 if (!wstr) return -1; 00695 MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, wstr, len); 00696 citW.pszText = wstr; 00697 } 00698 ret = COMBOEX_InsertItemW(infoPtr, &citW); 00699 00700 Free(wstr); 00701 00702 return ret; 00703 } 00704 00705 00706 static DWORD 00707 COMBOEX_SetExtendedStyle (COMBOEX_INFO *infoPtr, DWORD mask, DWORD style) 00708 { 00709 DWORD dwTemp; 00710 00711 TRACE("(mask=x%08x, style=0x%08x)\n", mask, style); 00712 00713 dwTemp = infoPtr->dwExtStyle; 00714 00715 if (mask) 00716 infoPtr->dwExtStyle = (infoPtr->dwExtStyle & ~mask) | style; 00717 else 00718 infoPtr->dwExtStyle = style; 00719 00720 /* see if we need to change the word break proc on the edit */ 00721 if ((infoPtr->dwExtStyle ^ dwTemp) & CBES_EX_PATHWORDBREAKPROC) 00722 SetPathWordBreakProc(infoPtr->hwndEdit, 00723 (infoPtr->dwExtStyle & CBES_EX_PATHWORDBREAKPROC) ? TRUE : FALSE); 00724 00725 /* test if the control's appearance has changed */ 00726 mask = CBES_EX_NOEDITIMAGE | CBES_EX_NOEDITIMAGEINDENT; 00727 if ((infoPtr->dwExtStyle & mask) != (dwTemp & mask)) { 00728 /* if state of EX_NOEDITIMAGE changes, invalidate all */ 00729 TRACE("EX_NOEDITIMAGE state changed to %d\n", 00730 infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE); 00731 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); 00732 COMBOEX_AdjustEditPos (infoPtr); 00733 if (infoPtr->hwndEdit) 00734 InvalidateRect (infoPtr->hwndEdit, NULL, TRUE); 00735 } 00736 00737 return dwTemp; 00738 } 00739 00740 00741 static HIMAGELIST COMBOEX_SetImageList (COMBOEX_INFO *infoPtr, HIMAGELIST himl) 00742 { 00743 HIMAGELIST himlTemp = infoPtr->himl; 00744 00745 TRACE("\n"); 00746 00747 infoPtr->himl = himl; 00748 00749 COMBOEX_ReSize (infoPtr); 00750 InvalidateRect (infoPtr->hwndCombo, NULL, TRUE); 00751 00752 /* reposition the Edit control based on whether icon exists */ 00753 COMBOEX_AdjustEditPos (infoPtr); 00754 return himlTemp; 00755 } 00756 00757 static BOOL COMBOEX_SetItemW (const COMBOEX_INFO *infoPtr, const COMBOBOXEXITEMW *cit) 00758 { 00759 INT_PTR index = cit->iItem; 00760 CBE_ITEMDATA *item; 00761 00762 if (TRACE_ON(comboex)) COMBOEX_DumpInput (cit); 00763 00764 /* if item number requested does not exist then return failure */ 00765 if ((index >= infoPtr->nb_items) || (index < -1)) return FALSE; 00766 00767 /* if the item is the edit control and there is no edit control, skip */ 00768 if ((index == -1) && !infoPtr->hwndEdit) return FALSE; 00769 00770 if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE; 00771 00772 /* add/change stuff to the internal item structure */ 00773 item->mask |= cit->mask; 00774 if (cit->mask & CBEIF_TEXT) { 00775 INT len = 0; 00776 00777 COMBOEX_FreeText(item); 00778 if (is_textW(cit->pszText)) len = strlenW(cit->pszText); 00779 if (len > 0) { 00780 item->pszText = Alloc ((len + 1)*sizeof(WCHAR)); 00781 if (!item->pszText) return FALSE; 00782 strcpyW(item->pszText, cit->pszText); 00783 } else if (cit->pszText == LPSTR_TEXTCALLBACKW) 00784 item->pszText = LPSTR_TEXTCALLBACKW; 00785 item->cchTextMax = cit->cchTextMax; 00786 } 00787 if (cit->mask & CBEIF_IMAGE) 00788 item->iImage = cit->iImage; 00789 if (cit->mask & CBEIF_SELECTEDIMAGE) 00790 item->iSelectedImage = cit->iSelectedImage; 00791 if (cit->mask & CBEIF_OVERLAY) 00792 item->iOverlay = cit->iOverlay; 00793 if (cit->mask & CBEIF_INDENT) 00794 item->iIndent = cit->iIndent; 00795 if (cit->mask & CBEIF_LPARAM) 00796 item->lParam = cit->lParam; 00797 00798 if (TRACE_ON(comboex)) COMBOEX_DumpItem (item); 00799 00800 /* if original request was to update edit control, do some fast foot work */ 00801 if (cit->iItem == -1 && cit->mask & CBEIF_TEXT) { 00802 COMBOEX_SetEditText (infoPtr, item); 00803 RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | RDW_INVALIDATE); 00804 } 00805 return TRUE; 00806 } 00807 00808 static BOOL COMBOEX_SetItemA (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA const *cit) 00809 { 00810 COMBOBOXEXITEMW citW; 00811 LPWSTR wstr = NULL; 00812 BOOL ret; 00813 00814 memcpy(&citW, cit, sizeof(COMBOBOXEXITEMA)); 00815 if ((cit->mask & CBEIF_TEXT) && is_textA(cit->pszText)) { 00816 INT len = MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, NULL, 0); 00817 wstr = Alloc ((len + 1)*sizeof(WCHAR)); 00818 if (!wstr) return FALSE; 00819 MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, wstr, len); 00820 citW.pszText = wstr; 00821 } 00822 ret = COMBOEX_SetItemW(infoPtr, &citW); 00823 00824 Free(wstr); 00825 00826 return ret; 00827 } 00828 00829 00830 static BOOL COMBOEX_SetUnicodeFormat (COMBOEX_INFO *infoPtr, BOOL value) 00831 { 00832 BOOL bTemp = infoPtr->unicode; 00833 00834 TRACE("to %s, was %s\n", value ? "TRUE":"FALSE", bTemp ? "TRUE":"FALSE"); 00835 00836 infoPtr->unicode = value; 00837 00838 return bTemp; 00839 } 00840 00841 00842 /* *** CB_xxx message support *** */ 00843 00844 static INT 00845 COMBOEX_FindStringExact (const COMBOEX_INFO *infoPtr, INT start, LPCWSTR str) 00846 { 00847 INT i; 00848 cmp_func_t cmptext = get_cmp_func(infoPtr); 00849 INT count = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0); 00850 00851 /* now search from after starting loc and wrapping back to start */ 00852 for(i=start+1; i<count; i++) { 00853 CBE_ITEMDATA *item = get_item_data(infoPtr, i); 00854 if ((LRESULT)item == CB_ERR) continue; 00855 if (cmptext(COMBOEX_GetText(infoPtr, item), str) == 0) return i; 00856 } 00857 for(i=0; i<=start; i++) { 00858 CBE_ITEMDATA *item = get_item_data(infoPtr, i); 00859 if ((LRESULT)item == CB_ERR) continue; 00860 if (cmptext(COMBOEX_GetText(infoPtr, item), str) == 0) return i; 00861 } 00862 return CB_ERR; 00863 } 00864 00865 00866 static DWORD_PTR COMBOEX_GetItemData (const COMBOEX_INFO *infoPtr, INT_PTR index) 00867 { 00868 CBE_ITEMDATA const *item1; 00869 CBE_ITEMDATA const *item2; 00870 DWORD_PTR ret = 0; 00871 00872 item1 = get_item_data(infoPtr, index); 00873 if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) { 00874 item2 = COMBOEX_FindItem (infoPtr, index); 00875 if (item2 != item1) { 00876 ERR("data structures damaged!\n"); 00877 return CB_ERR; 00878 } 00879 if (item1->mask & CBEIF_LPARAM) ret = item1->lParam; 00880 TRACE("returning 0x%08lx\n", ret); 00881 } else { 00882 ret = (DWORD_PTR)item1; 00883 TRACE("non-valid result from combo, returning 0x%08lx\n", ret); 00884 } 00885 return ret; 00886 } 00887 00888 00889 static INT COMBOEX_SetCursel (COMBOEX_INFO *infoPtr, INT_PTR index) 00890 { 00891 CBE_ITEMDATA *item; 00892 INT sel; 00893 00894 if (!(item = COMBOEX_FindItem(infoPtr, index))) 00895 return SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0); 00896 00897 TRACE("selecting item %ld text=%s\n", index, debugstr_txt(item->pszText)); 00898 infoPtr->selected = index; 00899 00900 sel = (INT)SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0); 00901 COMBOEX_SetEditText (infoPtr, item); 00902 return sel; 00903 } 00904 00905 00906 static DWORD_PTR COMBOEX_SetItemData (const COMBOEX_INFO *infoPtr, INT_PTR index, DWORD_PTR data) 00907 { 00908 CBE_ITEMDATA *item1; 00909 CBE_ITEMDATA const *item2; 00910 00911 item1 = get_item_data(infoPtr, index); 00912 if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) { 00913 item2 = COMBOEX_FindItem (infoPtr, index); 00914 if (item2 != item1) { 00915 ERR("data structures damaged!\n"); 00916 return CB_ERR; 00917 } 00918 item1->mask |= CBEIF_LPARAM; 00919 item1->lParam = data; 00920 TRACE("setting lparam to 0x%08lx\n", data); 00921 return 0; 00922 } 00923 TRACE("non-valid result from combo %p\n", item1); 00924 return (DWORD_PTR)item1; 00925 } 00926 00927 00928 static INT COMBOEX_SetItemHeight (COMBOEX_INFO const *infoPtr, INT index, UINT height) 00929 { 00930 RECT cb_wrect, cbx_wrect, cbx_crect; 00931 00932 /* First, lets forward the message to the normal combo control 00933 just like Windows. */ 00934 if (infoPtr->hwndCombo) 00935 if (SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT, 00936 index, height) == CB_ERR) return CB_ERR; 00937 00938 GetWindowRect (infoPtr->hwndCombo, &cb_wrect); 00939 GetWindowRect (infoPtr->hwndSelf, &cbx_wrect); 00940 GetClientRect (infoPtr->hwndSelf, &cbx_crect); 00941 /* the height of comboex as height of the combo + comboex border */ 00942 height = cb_wrect.bottom-cb_wrect.top 00943 + cbx_wrect.bottom-cbx_wrect.top 00944 - (cbx_crect.bottom-cbx_crect.top); 00945 TRACE("EX window=(%s), client=(%s)\n", 00946 wine_dbgstr_rect(&cbx_wrect), wine_dbgstr_rect(&cbx_crect)); 00947 TRACE("CB window=(%s), EX setting=(0,0)-(%d,%d)\n", 00948 wine_dbgstr_rect(&cbx_wrect), cbx_wrect.right-cbx_wrect.left, height); 00949 SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0, 00950 cbx_wrect.right-cbx_wrect.left, height, 00951 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); 00952 00953 return 0; 00954 } 00955 00956 00957 /* *** WM_xxx message support *** */ 00958 00959 00960 static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs) 00961 { 00962 static const WCHAR NIL[] = { 0 }; 00963 COMBOEX_INFO *infoPtr; 00964 LOGFONTW mylogfont; 00965 RECT win_rect; 00966 INT i; 00967 00968 /* allocate memory for info structure */ 00969 infoPtr = Alloc (sizeof(COMBOEX_INFO)); 00970 if (!infoPtr) return -1; 00971 00972 /* initialize info structure */ 00973 /* note that infoPtr is allocated zero-filled */ 00974 00975 infoPtr->hwndSelf = hwnd; 00976 infoPtr->selected = -1; 00977 00978 infoPtr->unicode = IsWindowUnicode (hwnd); 00979 infoPtr->hwndNotify = cs->hwndParent; 00980 00981 i = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); 00982 if ((i != NFR_ANSI) && (i != NFR_UNICODE)) { 00983 WARN("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i); 00984 i = NFR_ANSI; 00985 } 00986 infoPtr->NtfUnicode = (i == NFR_UNICODE); 00987 00988 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); 00989 00990 if (TRACE_ON(comboex)) { 00991 RECT client, rect; 00992 GetWindowRect(hwnd, &rect); 00993 GetClientRect(hwnd, &client); 00994 TRACE("EX window=(%s), client=(%s)\n", 00995 wine_dbgstr_rect(&rect), wine_dbgstr_rect(&client)); 00996 } 00997 00998 /* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */ 00999 /* specified. It then creates it's own version of the EDIT control */ 01000 /* and makes the ComboBox the parent. This is because a normal */ 01001 /* DROPDOWNLIST does not have an EDIT control, but we need one. */ 01002 /* We also need to place the edit control at the proper location */ 01003 /* (allow space for the icons). */ 01004 01005 infoPtr->hwndCombo = CreateWindowW (WC_COMBOBOXW, NIL, 01006 /* following line added to match native */ 01007 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL | 01008 CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST | 01009 /* was base and is necessary */ 01010 WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | 01011 GetWindowLongW (hwnd, GWL_STYLE), 01012 cs->y, cs->x, cs->cx, cs->cy, hwnd, 01013 (HMENU) GetWindowLongPtrW (hwnd, GWLP_ID), 01014 (HINSTANCE)GetWindowLongPtrW (hwnd, GWLP_HINSTANCE), NULL); 01015 01016 /* 01017 * native does the following at this point according to trace: 01018 * GetWindowThreadProcessId(hwndCombo,0) 01019 * GetCurrentThreadId() 01020 * GetWindowThreadProcessId(hwndCombo, &???) 01021 * GetCurrentProcessId() 01022 */ 01023 01024 SetWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID, 01025 (DWORD_PTR)hwnd); 01026 infoPtr->font = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0); 01027 01028 /* 01029 * Now create our own EDIT control so we can position it. 01030 * It is created only for CBS_DROPDOWN style 01031 */ 01032 if ((cs->style & CBS_DROPDOWNLIST) == CBS_DROPDOWN) { 01033 infoPtr->hwndEdit = CreateWindowExW (0, WC_EDITW, NIL, 01034 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_AUTOHSCROLL, 01035 0, 0, 0, 0, /* will set later */ 01036 infoPtr->hwndCombo, 01037 (HMENU) GetWindowLongPtrW (hwnd, GWLP_ID), 01038 (HINSTANCE)GetWindowLongPtrW (hwnd, GWLP_HINSTANCE), NULL); 01039 01040 /* native does the following at this point according to trace: 01041 * GetWindowThreadProcessId(hwndEdit,0) 01042 * GetCurrentThreadId() 01043 * GetWindowThreadProcessId(hwndEdit, &???) 01044 * GetCurrentProcessId() 01045 */ 01046 SetWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID, 01047 (DWORD_PTR)hwnd); 01048 01049 infoPtr->font = (HFONT)SendMessageW(infoPtr->hwndCombo, WM_GETFONT, 0, 0); 01050 } 01051 01052 /* 01053 * Locate the default font if necessary and then set it in 01054 * all associated controls 01055 */ 01056 if (!infoPtr->font) { 01057 SystemParametersInfoW (SPI_GETICONTITLELOGFONT, sizeof(mylogfont), 01058 &mylogfont, 0); 01059 infoPtr->font = infoPtr->defaultFont = CreateFontIndirectW (&mylogfont); 01060 } 01061 SendMessageW (infoPtr->hwndCombo, WM_SETFONT, (WPARAM)infoPtr->font, 0); 01062 if (infoPtr->hwndEdit) { 01063 SendMessageW (infoPtr->hwndEdit, WM_SETFONT, (WPARAM)infoPtr->font, 0); 01064 SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, EC_USEFONTINFO, 0); 01065 } 01066 01067 COMBOEX_ReSize (infoPtr); 01068 01069 /* Above is fairly certain, below is much less certain. */ 01070 01071 GetWindowRect(hwnd, &win_rect); 01072 01073 if (TRACE_ON(comboex)) { 01074 RECT client, rect; 01075 GetClientRect(hwnd, &client); 01076 GetWindowRect(infoPtr->hwndCombo, &rect); 01077 TRACE("EX window=(%s) client=(%s) CB wnd=(%s)\n", 01078 wine_dbgstr_rect(&win_rect), wine_dbgstr_rect(&client), 01079 wine_dbgstr_rect(&rect)); 01080 } 01081 SetWindowPos(infoPtr->hwndCombo, HWND_TOP, 0, 0, 01082 win_rect.right - win_rect.left, win_rect.bottom - win_rect.top, 01083 SWP_NOACTIVATE | SWP_NOREDRAW); 01084 01085 GetWindowRect(infoPtr->hwndCombo, &win_rect); 01086 TRACE("CB window=(%s)\n", wine_dbgstr_rect(&win_rect)); 01087 SetWindowPos(hwnd, HWND_TOP, 0, 0, 01088 win_rect.right - win_rect.left, win_rect.bottom - win_rect.top, 01089 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); 01090 01091 COMBOEX_AdjustEditPos (infoPtr); 01092 01093 /* 01094 * Create an item structure to represent the data in the 01095 * EDIT control. It is allocated zero-filled. 01096 */ 01097 infoPtr->edit = Alloc (sizeof (CBE_ITEMDATA)); 01098 if (!infoPtr->edit) { 01099 COMBOEX_Destroy(infoPtr); 01100 return -1; 01101 } 01102 01103 return 0; 01104 } 01105 01106 01107 static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam) 01108 { 01109 LRESULT lret; 01110 INT command = HIWORD(wParam); 01111 CBE_ITEMDATA *item = 0; 01112 WCHAR wintext[520]; 01113 INT cursel, n; 01114 INT_PTR oldItem; 01115 NMCBEENDEDITW cbeend; 01116 DWORD oldflags; 01117 HWND parent = infoPtr->hwndNotify; 01118 01119 TRACE("for command %d\n", command); 01120 01121 switch (command) 01122 { 01123 case CBN_DROPDOWN: 01124 SetFocus (infoPtr->hwndCombo); 01125 ShowWindow (infoPtr->hwndEdit, SW_HIDE); 01126 infoPtr->flags |= WCBE_ACTEDIT; 01127 return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); 01128 case CBN_CLOSEUP: 01129 SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); 01130 /* 01131 * from native trace of first dropdown after typing in URL in IE4 01132 * CB_GETCURSEL(Combo) 01133 * GetWindowText(Edit) 01134 * CB_GETCURSEL(Combo) 01135 * CB_GETCOUNT(Combo) 01136 * CB_GETITEMDATA(Combo, n) 01137 * WM_NOTIFY(parent, CBEN_ENDEDITA|W) 01138 * CB_GETCURSEL(Combo) 01139 * CB_SETCURSEL(COMBOEX, n) 01140 * SetFocus(Combo) 01141 * the rest is supposition 01142 */ 01143 ShowWindow (infoPtr->hwndEdit, SW_SHOW); 01144 InvalidateRect (infoPtr->hwndCombo, 0, TRUE); 01145 if (infoPtr->hwndEdit) InvalidateRect (infoPtr->hwndEdit, 0, TRUE); 01146 cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); 01147 if (cursel == -1) { 01148 cmp_func_t cmptext = get_cmp_func(infoPtr); 01149 /* find match from edit against those in Combobox */ 01150 GetWindowTextW (infoPtr->hwndEdit, wintext, 520); 01151 n = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0); 01152 for (cursel = 0; cursel < n; cursel++){ 01153 item = get_item_data(infoPtr, cursel); 01154 if ((INT_PTR)item == CB_ERR) break; 01155 if (!cmptext(COMBOEX_GetText(infoPtr, item), wintext)) break; 01156 } 01157 if ((cursel == n) || ((INT_PTR)item == CB_ERR)) { 01158 TRACE("failed to find match??? item=%p cursel=%d\n", 01159 item, cursel); 01160 if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit); 01161 return 0; 01162 } 01163 } 01164 else { 01165 item = get_item_data(infoPtr, cursel); 01166 if ((INT_PTR)item == CB_ERR) { 01167 TRACE("failed to find match??? item=%p cursel=%d\n", 01168 item, cursel); 01169 if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit); 01170 return 0; 01171 } 01172 } 01173 01174 /* Save flags for testing and reset them */ 01175 oldflags = infoPtr->flags; 01176 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); 01177 01178 if (oldflags & WCBE_ACTEDIT) { 01179 cbeend.fChanged = (oldflags & WCBE_EDITCHG); 01180 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, 01181 CB_GETCURSEL, 0, 0); 01182 cbeend.iWhy = CBENF_DROPDOWN; 01183 01184 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, COMBOEX_GetText(infoPtr, item))) return 0; 01185 } 01186 01187 /* if selection has changed the set the new current selection */ 01188 cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); 01189 if ((oldflags & WCBE_EDITCHG) || (cursel != infoPtr->selected)) { 01190 infoPtr->selected = cursel; 01191 SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, cursel, 0); 01192 SetFocus(infoPtr->hwndCombo); 01193 } 01194 return 0; 01195 01196 case CBN_SELCHANGE: 01197 /* 01198 * CB_GETCURSEL(Combo) 01199 * CB_GETITEMDATA(Combo) < simulated by COMBOEX_FindItem 01200 * lstrlenA 01201 * WM_SETTEXT(Edit) 01202 * WM_GETTEXTLENGTH(Edit) 01203 * WM_GETTEXT(Edit) 01204 * EM_SETSEL(Edit, 0,0) 01205 * WM_GETTEXTLENGTH(Edit) 01206 * WM_GETTEXT(Edit) 01207 * EM_SETSEL(Edit, 0,len) 01208 * return WM_COMMAND to parent 01209 */ 01210 oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); 01211 if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) { 01212 ERR("item %ld not found. Problem!\n", oldItem); 01213 break; 01214 } 01215 infoPtr->selected = oldItem; 01216 COMBOEX_SetEditText (infoPtr, item); 01217 return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); 01218 01219 case CBN_SELENDOK: 01220 case CBN_SELENDCANCEL: 01221 /* 01222 * We have to change the handle since we are the control 01223 * issuing the message. IE4 depends on this. 01224 */ 01225 return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); 01226 01227 case CBN_KILLFOCUS: 01228 /* 01229 * from native trace: 01230 * 01231 * pass to parent 01232 * WM_GETTEXT(Edit, 104) 01233 * CB_GETCURSEL(Combo) rets -1 01234 * WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS 01235 * CB_GETCURSEL(Combo) 01236 * InvalidateRect(Combo, 0, 0) 01237 * return 0 01238 */ 01239 SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); 01240 if (infoPtr->flags & WCBE_ACTEDIT) { 01241 GetWindowTextW (infoPtr->hwndEdit, wintext, 260); 01242 cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG); 01243 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, 01244 CB_GETCURSEL, 0, 0); 01245 cbeend.iWhy = CBENF_KILLFOCUS; 01246 01247 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); 01248 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, wintext)) return 0; 01249 } 01250 /* possible CB_GETCURSEL */ 01251 InvalidateRect (infoPtr->hwndCombo, 0, 0); 01252 return 0; 01253 01254 case CBN_SETFOCUS: 01255 return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); 01256 01257 default: 01258 /* 01259 * We have to change the handle since we are the control 01260 * issuing the message. IE4 depends on this. 01261 * We also need to set the focus back to the Edit control 01262 * after passing the command to the parent of the ComboEx. 01263 */ 01264 lret = SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); 01265 if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit); 01266 return lret; 01267 } 01268 return 0; 01269 } 01270 01271 01272 static BOOL COMBOEX_WM_DeleteItem (COMBOEX_INFO *infoPtr, DELETEITEMSTRUCT const *dis) 01273 { 01274 CBE_ITEMDATA *item, *olditem; 01275 NMCOMBOBOXEXW nmcit; 01276 UINT i; 01277 01278 TRACE("CtlType=%08x, CtlID=%08x, itemID=%08x, hwnd=%p, data=%08lx\n", 01279 dis->CtlType, dis->CtlID, dis->itemID, dis->hwndItem, dis->itemData); 01280 01281 if (dis->itemID >= infoPtr->nb_items) return FALSE; 01282 01283 olditem = infoPtr->items; 01284 i = infoPtr->nb_items - 1; 01285 01286 if (i == dis->itemID) { 01287 infoPtr->items = infoPtr->items->next; 01288 } 01289 else { 01290 item = olditem; 01291 i--; 01292 01293 /* find the prior item in the list */ 01294 while (item->next && (i > dis->itemID)) { 01295 item = item->next; 01296 i--; 01297 } 01298 if (!item->next || (i != dis->itemID)) { 01299 ERR("COMBOBOXEX item structures broken. Please report!\n"); 01300 return FALSE; 01301 } 01302 olditem = item->next; 01303 item->next = item->next->next; 01304 } 01305 infoPtr->nb_items--; 01306 01307 memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem)); 01308 nmcit.ceItem.mask=~0; 01309 COMBOEX_CopyItem (olditem, &nmcit.ceItem); 01310 COMBOEX_NotifyItem (infoPtr, CBEN_DELETEITEM, &nmcit); 01311 01312 COMBOEX_FreeText(olditem); 01313 Free(olditem); 01314 01315 return TRUE; 01316 } 01317 01318 01319 static LRESULT COMBOEX_DrawItem (const COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT const *dis) 01320 { 01321 static const WCHAR nil[] = { 0 }; 01322 CBE_ITEMDATA *item = 0; 01323 SIZE txtsize; 01324 RECT rect; 01325 LPCWSTR str = nil; 01326 UINT xbase, x, y; 01327 INT len; 01328 COLORREF nbkc, ntxc, bkc, txc; 01329 int drawimage, drawstate, xioff; 01330 01331 TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n", 01332 dis->CtlType, dis->CtlID); 01333 TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n", 01334 dis->itemID, dis->itemAction, dis->itemState); 01335 TRACE("hWnd=%p hDC=%p (%s) itemData=0x%08lx\n", 01336 dis->hwndItem, dis->hDC, wine_dbgstr_rect(&dis->rcItem), dis->itemData); 01337 01338 /* MSDN says: */ 01339 /* "itemID - Specifies the menu item identifier for a menu */ 01340 /* item or the index of the item in a list box or combo box. */ 01341 /* For an empty list box or combo box, this member can be -1. */ 01342 /* This allows the application to draw only the focus */ 01343 /* rectangle at the coordinates specified by the rcItem */ 01344 /* member even though there are no items in the control. */ 01345 /* This indicates to the user whether the list box or combo */ 01346 /* box has the focus. How the bits are set in the itemAction */ 01347 /* member determines whether the rectangle is to be drawn as */ 01348 /* though the list box or combo box has the focus. */ 01349 if (dis->itemID == 0xffffffff) { 01350 if ( ( (dis->itemAction & ODA_FOCUS) && (dis->itemState & ODS_SELECTED)) || 01351 ( (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) && (dis->itemState & ODS_FOCUS) ) ) { 01352 01353 TRACE("drawing item -1 special focus, rect=(%s)\n", 01354 wine_dbgstr_rect(&dis->rcItem)); 01355 } 01356 else if ((dis->CtlType == ODT_COMBOBOX) && 01357 (dis->itemAction == ODA_DRAWENTIRE)) { 01358 /* draw of edit control data */ 01359 01360 if (TRACE_ON(comboex)) { 01361 RECT exrc, cbrc, edrc; 01362 GetWindowRect (infoPtr->hwndSelf, &exrc); 01363 GetWindowRect (infoPtr->hwndCombo, &cbrc); 01364 edrc.left = edrc.top = edrc.right = edrc.bottom = -1; 01365 if (infoPtr->hwndEdit) GetWindowRect (infoPtr->hwndEdit, &edrc); 01366 TRACE("window rects ex=(%s), cb=(%s), ed=(%s)\n", 01367 wine_dbgstr_rect(&exrc), wine_dbgstr_rect(&cbrc), 01368 wine_dbgstr_rect(&edrc)); 01369 } 01370 } 01371 else { 01372 ERR("NOT drawing item -1 special focus, rect=(%s), action=%08x, state=%08x\n", 01373 wine_dbgstr_rect(&dis->rcItem), 01374 dis->itemAction, dis->itemState); 01375 return 0; 01376 } 01377 } 01378 01379 /* If draw item is -1 (edit control) setup the item pointer */ 01380 if (dis->itemID == 0xffffffff) { 01381 item = infoPtr->edit; 01382 01383 if (infoPtr->hwndEdit) { 01384 INT len; 01385 01386 /* free previous text of edit item */ 01387 COMBOEX_FreeText(item); 01388 item->mask &= ~CBEIF_TEXT; 01389 if( (len = GetWindowTextLengthW(infoPtr->hwndEdit)) ) { 01390 item->mask |= CBEIF_TEXT; 01391 item->pszText = Alloc ((len + 1)*sizeof(WCHAR)); 01392 if (item->pszText) 01393 GetWindowTextW(infoPtr->hwndEdit, item->pszText, len+1); 01394 01395 TRACE("edit control hwndEdit=%p, text len=%d str=%s\n", 01396 infoPtr->hwndEdit, len, debugstr_txt(item->pszText)); 01397 } 01398 } 01399 } 01400 01401 01402 /* if the item pointer is not set, then get the data and locate it */ 01403 if (!item) { 01404 item = get_item_data(infoPtr, dis->itemID); 01405 if (item == (CBE_ITEMDATA *)CB_ERR) { 01406 ERR("invalid item for id %d\n", dis->itemID); 01407 return 0; 01408 } 01409 } 01410 01411 if (TRACE_ON(comboex)) COMBOEX_DumpItem (item); 01412 01413 xbase = CBE_STARTOFFSET; 01414 if ((item->mask & CBEIF_INDENT) && (dis->itemState & ODS_COMBOEXLBOX)) { 01415 INT indent = item->iIndent; 01416 if (indent == I_INDENTCALLBACK) { 01417 NMCOMBOBOXEXW nmce; 01418 ZeroMemory(&nmce, sizeof(nmce)); 01419 nmce.ceItem.mask = CBEIF_INDENT; 01420 nmce.ceItem.lParam = item->lParam; 01421 nmce.ceItem.iItem = dis->itemID; 01422 COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); 01423 if (nmce.ceItem.mask & CBEIF_DI_SETITEM) 01424 item->iIndent = nmce.ceItem.iIndent; 01425 indent = nmce.ceItem.iIndent; 01426 } 01427 xbase += (indent * CBE_INDENT); 01428 } 01429 01430 drawimage = -2; 01431 drawstate = ILD_NORMAL; 01432 if (item->mask & CBEIF_IMAGE) 01433 drawimage = item->iImage; 01434 if (dis->itemState & ODS_COMBOEXLBOX) { 01435 /* drawing listbox entry */ 01436 if (dis->itemState & ODS_SELECTED) { 01437 if (item->mask & CBEIF_SELECTEDIMAGE) 01438 drawimage = item->iSelectedImage; 01439 drawstate = ILD_SELECTED; 01440 } 01441 } else { 01442 /* drawing combo/edit entry */ 01443 if (IsWindowVisible(infoPtr->hwndEdit)) { 01444 /* if we have an edit control, the slave the 01445 * selection state to the Edit focus state 01446 */ 01447 if (infoPtr->flags & WCBE_EDITFOCUSED) { 01448 if (item->mask & CBEIF_SELECTEDIMAGE) 01449 drawimage = item->iSelectedImage; 01450 drawstate = ILD_SELECTED; 01451 } 01452 } else { 01453 /* if we don't have an edit control, use 01454 * the requested state. 01455 */ 01456 if (dis->itemState & ODS_SELECTED) { 01457 if (item->mask & CBEIF_SELECTEDIMAGE) 01458 drawimage = item->iSelectedImage; 01459 drawstate = ILD_SELECTED; 01460 } 01461 } 01462 } 01463 01464 if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) { 01465 IMAGEINFO iinfo; 01466 iinfo.rcImage.left = iinfo.rcImage.right = 0; 01467 ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo); 01468 xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP; 01469 } else xioff = 0; 01470 01471 /* setup pointer to text to be drawn */ 01472 str = COMBOEX_GetText(infoPtr, item); 01473 if (!str) str = nil; 01474 01475 len = strlenW (str); 01476 GetTextExtentPoint32W (dis->hDC, str, len, &txtsize); 01477 01478 if (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) { 01479 int overlay = item->iOverlay; 01480 01481 if (drawimage == I_IMAGECALLBACK) { 01482 NMCOMBOBOXEXW nmce; 01483 ZeroMemory(&nmce, sizeof(nmce)); 01484 nmce.ceItem.mask = (drawstate == ILD_NORMAL) ? CBEIF_IMAGE : CBEIF_SELECTEDIMAGE; 01485 nmce.ceItem.lParam = item->lParam; 01486 nmce.ceItem.iItem = dis->itemID; 01487 COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); 01488 if (drawstate == ILD_NORMAL) { 01489 if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iImage = nmce.ceItem.iImage; 01490 drawimage = nmce.ceItem.iImage; 01491 } else if (drawstate == ILD_SELECTED) { 01492 if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iSelectedImage = nmce.ceItem.iSelectedImage; 01493 drawimage = nmce.ceItem.iSelectedImage; 01494 } else ERR("Bad draw state = %d\n", drawstate); 01495 } 01496 01497 if (overlay == I_IMAGECALLBACK) { 01498 NMCOMBOBOXEXW nmce; 01499 ZeroMemory(&nmce, sizeof(nmce)); 01500 nmce.ceItem.mask = CBEIF_OVERLAY; 01501 nmce.ceItem.lParam = item->lParam; 01502 nmce.ceItem.iItem = dis->itemID; 01503 COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); 01504 if (nmce.ceItem.mask & CBEIF_DI_SETITEM) 01505 item->iOverlay = nmce.ceItem.iOverlay; 01506 overlay = nmce.ceItem.iOverlay; 01507 } 01508 01509 if (drawimage >= 0 && 01510 !(infoPtr->dwExtStyle & (CBES_EX_NOEDITIMAGE | CBES_EX_NOEDITIMAGEINDENT))) { 01511 if (overlay > 0) ImageList_SetOverlayImage (infoPtr->himl, overlay, 1); 01512 ImageList_Draw (infoPtr->himl, drawimage, dis->hDC, xbase, dis->rcItem.top, 01513 drawstate | (overlay > 0 ? INDEXTOOVERLAYMASK(1) : 0)); 01514 } 01515 01516 /* now draw the text */ 01517 if (!IsWindowVisible (infoPtr->hwndEdit)) { 01518 nbkc = (dis->itemState & ODS_SELECTED) ? 01519 comctl32_color.clrHighlight : comctl32_color.clrWindow; 01520 bkc = SetBkColor (dis->hDC, nbkc); 01521 ntxc = (dis->itemState & ODS_SELECTED) ? 01522 comctl32_color.clrHighlightText : comctl32_color.clrWindowText; 01523 txc = SetTextColor (dis->hDC, ntxc); 01524 x = xbase + xioff; 01525 y = dis->rcItem.top + 01526 (dis->rcItem.bottom - dis->rcItem.top - txtsize.cy) / 2; 01527 rect.left = x; 01528 rect.right = x + txtsize.cx; 01529 rect.top = dis->rcItem.top + 1; 01530 rect.bottom = dis->rcItem.bottom - 1; 01531 TRACE("drawing item %d text, rect=(%s)\n", 01532 dis->itemID, wine_dbgstr_rect(&rect)); 01533 ExtTextOutW (dis->hDC, x, y, ETO_OPAQUE | ETO_CLIPPED, 01534 &rect, str, len, 0); 01535 SetBkColor (dis->hDC, bkc); 01536 SetTextColor (dis->hDC, txc); 01537 } 01538 } 01539 01540 if (dis->itemAction & ODA_FOCUS) { 01541 rect.left = xbase + xioff - 1; 01542 rect.right = rect.left + txtsize.cx + 2; 01543 rect.top = dis->rcItem.top; 01544 rect.bottom = dis->rcItem.bottom; 01545 DrawFocusRect(dis->hDC, &rect); 01546 } 01547 01548 return 0; 01549 } 01550 01551 01552 static void COMBOEX_ResetContent (COMBOEX_INFO *infoPtr) 01553 { 01554 if (infoPtr->items) 01555 { 01556 CBE_ITEMDATA *item, *next; 01557 01558 item = infoPtr->items; 01559 while (item) { 01560 next = item->next; 01561 COMBOEX_FreeText (item); 01562 Free (item); 01563 item = next; 01564 } 01565 infoPtr->items = 0; 01566 } 01567 01568 infoPtr->selected = -1; 01569 infoPtr->nb_items = 0; 01570 } 01571 01572 01573 static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr) 01574 { 01575 if (infoPtr->hwndCombo) 01576 RemoveWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID); 01577 01578 if (infoPtr->hwndEdit) 01579 RemoveWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID); 01580 01581 COMBOEX_FreeText (infoPtr->edit); 01582 Free (infoPtr->edit); 01583 infoPtr->edit = 0; 01584 01585 COMBOEX_ResetContent (infoPtr); 01586 01587 if (infoPtr->defaultFont) 01588 DeleteObject (infoPtr->defaultFont); 01589 01590 SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); 01591 01592 /* free comboex info data */ 01593 Free (infoPtr); 01594 01595 return 0; 01596 } 01597 01598 01599 static LRESULT COMBOEX_Enable (COMBOEX_INFO *infoPtr, BOOL enable) 01600 { 01601 TRACE("hwnd=%p, enable=%s\n", infoPtr->hwndSelf, enable ? "TRUE":"FALSE"); 01602 01603 if (infoPtr->hwndEdit) 01604 EnableWindow(infoPtr->hwndEdit, enable); 01605 01606 EnableWindow(infoPtr->hwndCombo, enable); 01607 01608 /* Force the control to repaint when the enabled state changes. */ 01609 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 01610 01611 return 1; 01612 } 01613 01614 01615 static LRESULT COMBOEX_MeasureItem (COMBOEX_INFO const *infoPtr, MEASUREITEMSTRUCT *mis) 01616 { 01617 static const WCHAR strW[] = { 'W', 0 }; 01618 SIZE mysize; 01619 HDC hdc; 01620 01621 hdc = GetDC (0); 01622 GetTextExtentPointW (hdc, strW, 1, &mysize); 01623 ReleaseDC (0, hdc); 01624 mis->itemHeight = mysize.cy + CBE_EXTRA; 01625 01626 TRACE("adjusted height hwnd=%p, height=%d\n", 01627 infoPtr->hwndSelf, mis->itemHeight); 01628 01629 return 0; 01630 } 01631 01632 01633 static LRESULT COMBOEX_NCCreate (HWND hwnd) 01634 { 01635 /* WARNING: The COMBOEX_INFO structure is not yet created */ 01636 DWORD oldstyle, newstyle; 01637 01638 oldstyle = (DWORD)GetWindowLongW (hwnd, GWL_STYLE); 01639 newstyle = oldstyle & ~(WS_VSCROLL | WS_HSCROLL | WS_BORDER); 01640 if (newstyle != oldstyle) { 01641 TRACE("req style %08x, resetting style %08x\n", 01642 oldstyle, newstyle); 01643 SetWindowLongW (hwnd, GWL_STYLE, newstyle); 01644 } 01645 return 1; 01646 } 01647 01648 01649 static LRESULT COMBOEX_NotifyFormat (COMBOEX_INFO *infoPtr, LPARAM lParam) 01650 { 01651 if (lParam == NF_REQUERY) { 01652 INT i = SendMessageW(infoPtr->hwndNotify, 01653 WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); 01654 infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0; 01655 } 01656 return infoPtr->NtfUnicode ? NFR_UNICODE : NFR_ANSI; 01657 } 01658 01659 01660 static LRESULT COMBOEX_Size (COMBOEX_INFO *infoPtr, INT width, INT height) 01661 { 01662 TRACE("(width=%d, height=%d)\n", width, height); 01663 01664 MoveWindow (infoPtr->hwndCombo, 0, 0, width, height, TRUE); 01665 01666 COMBOEX_AdjustEditPos (infoPtr); 01667 01668 return 0; 01669 } 01670 01671 01672 static LRESULT COMBOEX_SetRedraw(const COMBOEX_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 01673 { 01674 LRESULT ret = DefWindowProcW( infoPtr->hwndSelf, WM_SETREDRAW, wParam, lParam ); 01675 if (wParam) RedrawWindow( infoPtr->hwndSelf, NULL, 0, RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN ); 01676 return ret; 01677 } 01678 01679 01680 static LRESULT COMBOEX_WindowPosChanging (const COMBOEX_INFO *infoPtr, WINDOWPOS *wp) 01681 { 01682 RECT cbx_wrect, cbx_crect, cb_wrect; 01683 INT width, height; 01684 01685 GetWindowRect (infoPtr->hwndSelf, &cbx_wrect); 01686 GetClientRect (infoPtr->hwndSelf, &cbx_crect); 01687 GetWindowRect (infoPtr->hwndCombo, &cb_wrect); 01688 01689 /* width is winpos value + border width of comboex */ 01690 width = wp->cx 01691 + (cbx_wrect.right-cbx_wrect.left) 01692 - (cbx_crect.right-cbx_crect.left); 01693 01694 TRACE("winpos=(%d,%d %dx%d) flags=0x%08x\n", 01695 wp->x, wp->y, wp->cx, wp->cy, wp->flags); 01696 TRACE("EX window=(%s), client=(%s)\n", 01697 wine_dbgstr_rect(&cbx_wrect), wine_dbgstr_rect(&cbx_crect)); 01698 TRACE("CB window=(%s), EX setting=(0,0)-(%d,%d)\n", 01699 wine_dbgstr_rect(&cbx_wrect), width, cb_wrect.bottom-cb_wrect.top); 01700 01701 if (width) SetWindowPos (infoPtr->hwndCombo, HWND_TOP, 0, 0, 01702 width, 01703 cb_wrect.bottom-cb_wrect.top, 01704 SWP_NOACTIVATE); 01705 01706 GetWindowRect (infoPtr->hwndCombo, &cb_wrect); 01707 01708 /* height is combo window height plus border width of comboex */ 01709 height = (cb_wrect.bottom-cb_wrect.top) 01710 + (cbx_wrect.bottom-cbx_wrect.top) 01711 - (cbx_crect.bottom-cbx_crect.top); 01712 wp->cy = height; 01713 if (infoPtr->hwndEdit) { 01714 COMBOEX_AdjustEditPos (infoPtr); 01715 InvalidateRect (infoPtr->hwndCombo, 0, TRUE); 01716 } 01717 01718 return 0; 01719 } 01720 01721 static LRESULT CALLBACK 01722 COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 01723 UINT_PTR uId, DWORD_PTR ref_data) 01724 { 01725 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr ((HWND)ref_data); 01726 NMCBEENDEDITW cbeend; 01727 WCHAR edit_text[260]; 01728 COLORREF obkc; 01729 HDC hDC; 01730 RECT rect; 01731 LRESULT lret; 01732 01733 TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx, info_ptr=%p\n", 01734 hwnd, uMsg, wParam, lParam, infoPtr); 01735 01736 if (!infoPtr) return 0; 01737 01738 switch (uMsg) 01739 { 01740 01741 case WM_CHAR: 01742 /* handle (ignore) the return character */ 01743 if (wParam == VK_RETURN) return 0; 01744 /* all other characters pass into the real Edit */ 01745 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 01746 01747 case WM_ERASEBKGND: 01748 /* 01749 * The following was determined by traces of the native 01750 */ 01751 hDC = (HDC) wParam; 01752 obkc = SetBkColor (hDC, comctl32_color.clrWindow); 01753 GetClientRect (hwnd, &rect); 01754 TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect)); 01755 ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0); 01756 SetBkColor (hDC, obkc); 01757 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 01758 01759 case WM_KEYDOWN: { 01760 INT_PTR oldItem, selected; 01761 CBE_ITEMDATA *item; 01762 01763 switch ((INT)wParam) 01764 { 01765 case VK_ESCAPE: 01766 /* native version seems to do following for COMBOEX */ 01767 /* 01768 * GetWindowTextW(Edit,&?, 0x104) x 01769 * CB_GETCURSEL to Combo rets -1 x 01770 * WM_NOTIFY to COMBOEX parent (rebar) x 01771 * (CBEN_ENDEDIT{A|W} 01772 * fChanged = FALSE x 01773 * inewSelection = -1 x 01774 * txt="www.hoho" x 01775 * iWhy = 3 x 01776 * CB_GETCURSEL to Combo rets -1 x 01777 * InvalidateRect(Combo, 0) x 01778 * WM_SETTEXT to Edit x 01779 * EM_SETSEL to Edit (0,0) x 01780 * EM_SETSEL to Edit (0,-1) x 01781 * RedrawWindow(Combo, 0, 0, 5) x 01782 */ 01783 TRACE("special code for VK_ESCAPE\n"); 01784 01785 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); 01786 01787 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); 01788 cbeend.fChanged = FALSE; 01789 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, 01790 CB_GETCURSEL, 0, 0); 01791 cbeend.iWhy = CBENF_ESCAPE; 01792 01793 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) return 0; 01794 oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); 01795 InvalidateRect (infoPtr->hwndCombo, 0, 0); 01796 if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) { 01797 ERR("item %ld not found. Problem!\n", oldItem); 01798 break; 01799 } 01800 infoPtr->selected = oldItem; 01801 COMBOEX_SetEditText (infoPtr, item); 01802 RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | 01803 RDW_INVALIDATE); 01804 break; 01805 01806 case VK_RETURN: 01807 /* native version seems to do following for COMBOEX */ 01808 /* 01809 * GetWindowTextW(Edit,&?, 0x104) x 01810 * CB_GETCURSEL to Combo rets -1 x 01811 * CB_GETCOUNT to Combo rets 0 01812 * if >0 loop 01813 * CB_GETITEMDATA to match 01814 * *** above 3 lines simulated by FindItem x 01815 * WM_NOTIFY to COMBOEX parent (rebar) x 01816 * (CBEN_ENDEDIT{A|W} x 01817 * fChanged = TRUE (-1) x 01818 * iNewSelection = -1 or selected x 01819 * txt= x 01820 * iWhy = 2 (CBENF_RETURN) x 01821 * CB_GETCURSEL to Combo rets -1 x 01822 * if -1 send CB_SETCURSEL to Combo -1 x 01823 * InvalidateRect(Combo, 0, 0) x 01824 * SetFocus(Edit) x 01825 * CallWindowProc(406615a8, Edit, 0x100, 0xd, 0x1c0001) 01826 */ 01827 01828 TRACE("special code for VK_RETURN\n"); 01829 01830 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); 01831 01832 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); 01833 selected = SendMessageW (infoPtr->hwndCombo, 01834 CB_GETCURSEL, 0, 0); 01835 01836 if (selected != -1) { 01837 cmp_func_t cmptext = get_cmp_func(infoPtr); 01838 item = COMBOEX_FindItem (infoPtr, selected); 01839 TRACE("handling VK_RETURN, selected = %ld, selected_text=%s\n", 01840 selected, debugstr_txt(item->pszText)); 01841 TRACE("handling VK_RETURN, edittext=%s\n", 01842 debugstr_w(edit_text)); 01843 if (cmptext (COMBOEX_GetText(infoPtr, item), edit_text)) { 01844 /* strings not equal -- indicate edit has changed */ 01845 selected = -1; 01846 } 01847 } 01848 01849 cbeend.iNewSelection = selected; 01850 cbeend.fChanged = TRUE; 01851 cbeend.iWhy = CBENF_RETURN; 01852 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) { 01853 /* abort the change, restore previous */ 01854 TRACE("Notify requested abort of change\n"); 01855 COMBOEX_SetEditText (infoPtr, infoPtr->edit); 01856 RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | 01857 RDW_INVALIDATE); 01858 return 0; 01859 } 01860 oldItem = SendMessageW (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0); 01861 if (oldItem != -1) { 01862 /* if something is selected, then deselect it */ 01863 SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, -1, 0); 01864 } 01865 InvalidateRect (infoPtr->hwndCombo, 0, 0); 01866 SetFocus(infoPtr->hwndEdit); 01867 break; 01868 01869 case VK_UP: 01870 case VK_DOWN: 01871 { 01872 INT step = wParam == VK_DOWN ? 1 : -1; 01873 01874 oldItem = SendMessageW (infoPtr->hwndSelf, CB_GETCURSEL, 0, 0); 01875 if (oldItem >= 0 && oldItem + step >= 0) 01876 SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, oldItem + step, 0); 01877 return 0; 01878 } 01879 default: 01880 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 01881 } 01882 return 0; 01883 } 01884 01885 case WM_SETFOCUS: 01886 /* remember the focus to set state of icon */ 01887 lret = DefSubclassProc(hwnd, uMsg, wParam, lParam); 01888 infoPtr->flags |= WCBE_EDITFOCUSED; 01889 return lret; 01890 01891 case WM_KILLFOCUS: 01892 /* 01893 * do NOTIFY CBEN_ENDEDIT with CBENF_KILLFOCUS 01894 */ 01895 infoPtr->flags &= ~WCBE_EDITFOCUSED; 01896 if (infoPtr->flags & WCBE_ACTEDIT) { 01897 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); 01898 01899 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); 01900 cbeend.fChanged = FALSE; 01901 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, 01902 CB_GETCURSEL, 0, 0); 01903 cbeend.iWhy = CBENF_KILLFOCUS; 01904 01905 COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text); 01906 } 01907 /* fall through */ 01908 01909 default: 01910 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 01911 } 01912 } 01913 01914 01915 static LRESULT CALLBACK 01916 COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 01917 UINT_PTR uId, DWORD_PTR ref_data) 01918 { 01919 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr ((HWND)ref_data); 01920 NMCBEENDEDITW cbeend; 01921 NMMOUSE nmmse; 01922 COLORREF obkc; 01923 HDC hDC; 01924 HWND focusedhwnd; 01925 RECT rect; 01926 POINT pt; 01927 WCHAR edit_text[260]; 01928 01929 TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx, info_ptr=%p\n", 01930 hwnd, uMsg, wParam, lParam, infoPtr); 01931 01932 if (!infoPtr) return 0; 01933 01934 switch (uMsg) 01935 { 01936 01937 case WM_DRAWITEM: 01938 /* 01939 * The only way this message should come is from the 01940 * child Listbox issuing the message. Flag this so 01941 * that ComboEx knows this is listbox. 01942 */ 01943 ((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX; 01944 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 01945 01946 case WM_ERASEBKGND: 01947 /* 01948 * The following was determined by traces of the native 01949 */ 01950 hDC = (HDC) wParam; 01951 obkc = SetBkColor (hDC, comctl32_color.clrWindow); 01952 GetClientRect (hwnd, &rect); 01953 TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect)); 01954 ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0); 01955 SetBkColor (hDC, obkc); 01956 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 01957 01958 case WM_SETCURSOR: 01959 /* 01960 * WM_NOTIFY to comboex parent (rebar) 01961 * with NM_SETCURSOR with extra words of 0,0,0,0,0x02010001 01962 * CallWindowProc (previous) 01963 */ 01964 nmmse.dwItemSpec = 0; 01965 nmmse.dwItemData = 0; 01966 nmmse.pt.x = 0; 01967 nmmse.pt.y = 0; 01968 nmmse.dwHitInfo = lParam; 01969 COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse); 01970 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 01971 01972 case WM_LBUTTONDOWN: 01973 GetClientRect (hwnd, &rect); 01974 rect.bottom = rect.top + SendMessageW(infoPtr->hwndSelf, 01975 CB_GETITEMHEIGHT, -1, 0); 01976 rect.left = rect.right - GetSystemMetrics(SM_CXVSCROLL); 01977 pt.x = (short)LOWORD(lParam); 01978 pt.y = (short)HIWORD(lParam); 01979 if (PtInRect(&rect, pt)) 01980 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 01981 01982 infoPtr->flags |= WCBE_MOUSECAPTURED; 01983 SetCapture(hwnd); 01984 break; 01985 01986 case WM_LBUTTONUP: 01987 if (!(infoPtr->flags & WCBE_MOUSECAPTURED)) 01988 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 01989 01990 ReleaseCapture(); 01991 infoPtr->flags &= ~WCBE_MOUSECAPTURED; 01992 if (infoPtr->flags & WCBE_MOUSEDRAGGED) { 01993 infoPtr->flags &= ~WCBE_MOUSEDRAGGED; 01994 } else { 01995 SendMessageW(hwnd, CB_SHOWDROPDOWN, TRUE, 0); 01996 } 01997 break; 01998 01999 case WM_MOUSEMOVE: 02000 if ( (infoPtr->flags & WCBE_MOUSECAPTURED) && 02001 !(infoPtr->flags & WCBE_MOUSEDRAGGED)) { 02002 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); 02003 COMBOEX_NotifyDragBegin(infoPtr, edit_text); 02004 infoPtr->flags |= WCBE_MOUSEDRAGGED; 02005 } 02006 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 02007 02008 case WM_COMMAND: 02009 switch (HIWORD(wParam)) { 02010 02011 case EN_UPDATE: 02012 /* traces show that COMBOEX does not issue CBN_EDITUPDATE 02013 * on the EN_UPDATE 02014 */ 02015 return 0; 02016 02017 case EN_KILLFOCUS: 02018 /* 02019 * Native does: 02020 * 02021 * GetFocus() retns AA 02022 * GetWindowTextW(Edit) 02023 * CB_GETCURSEL(Combo) (got -1) 02024 * WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS 02025 * CB_GETCURSEL(Combo) (got -1) 02026 * InvalidateRect(Combo, 0, 0) 02027 * WM_KILLFOCUS(Combo, AA) 02028 * return 0; 02029 */ 02030 focusedhwnd = GetFocus(); 02031 if (infoPtr->flags & WCBE_ACTEDIT) { 02032 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); 02033 cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG); 02034 cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, 02035 CB_GETCURSEL, 0, 0); 02036 cbeend.iWhy = CBENF_KILLFOCUS; 02037 02038 infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); 02039 if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) return 0; 02040 } 02041 /* possible CB_GETCURSEL */ 02042 InvalidateRect (infoPtr->hwndCombo, 0, 0); 02043 if (focusedhwnd) 02044 SendMessageW (infoPtr->hwndCombo, WM_KILLFOCUS, 02045 (WPARAM)focusedhwnd, 0); 02046 return 0; 02047 02048 case EN_SETFOCUS: { 02049 /* 02050 * For EN_SETFOCUS this issues the same calls and messages 02051 * as the native seems to do. 02052 * 02053 * for some cases however native does the following: 02054 * (noticed after SetFocus during LBUTTONDOWN on 02055 * on dropdown arrow) 02056 * WM_GETTEXTLENGTH (Edit); 02057 * WM_GETTEXT (Edit, len+1, str); 02058 * EM_SETSEL (Edit, 0, 0); 02059 * WM_GETTEXTLENGTH (Edit); 02060 * WM_GETTEXT (Edit, len+1, str); 02061 * EM_SETSEL (Edit, 0, len); 02062 * WM_NOTIFY (parent, CBEN_BEGINEDIT) 02063 */ 02064 NMHDR hdr; 02065 02066 SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0); 02067 SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1); 02068 COMBOEX_Notify (infoPtr, CBEN_BEGINEDIT, &hdr); 02069 infoPtr->flags |= WCBE_ACTEDIT; 02070 infoPtr->flags &= ~WCBE_EDITCHG; /* no change yet */ 02071 return 0; 02072 } 02073 02074 case EN_CHANGE: { 02075 /* 02076 * For EN_CHANGE this issues the same calls and messages 02077 * as the native seems to do. 02078 */ 02079 WCHAR edit_text[260]; 02080 LPCWSTR lastwrk; 02081 cmp_func_t cmptext = get_cmp_func(infoPtr); 02082 02083 INT_PTR selected = SendMessageW (infoPtr->hwndCombo, 02084 CB_GETCURSEL, 0, 0); 02085 02086 /* lstrlenW( lastworkingURL ) */ 02087 02088 GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); 02089 if (selected == -1) { 02090 lastwrk = infoPtr->edit->pszText; 02091 } 02092 else { 02093 CBE_ITEMDATA *item = COMBOEX_FindItem (infoPtr, selected); 02094 lastwrk = COMBOEX_GetText(infoPtr, item); 02095 } 02096 02097 TRACE("handling EN_CHANGE, selected = %ld, selected_text=%s\n", 02098 selected, debugstr_w(lastwrk)); 02099 TRACE("handling EN_CHANGE, edittext=%s\n", 02100 debugstr_w(edit_text)); 02101 02102 /* cmptext is between lastworkingURL and GetWindowText */ 02103 if (cmptext (lastwrk, edit_text)) { 02104 /* strings not equal -- indicate edit has changed */ 02105 infoPtr->flags |= WCBE_EDITCHG; 02106 } 02107 SendMessageW ( infoPtr->hwndNotify, WM_COMMAND, 02108 MAKEWPARAM(GetDlgCtrlID (infoPtr->hwndSelf), 02109 CBN_EDITCHANGE), 02110 (LPARAM)infoPtr->hwndSelf); 02111 return 0; 02112 } 02113 02114 case LBN_SELCHANGE: 02115 /* 02116 * Therefore from traces there is no additional code here 02117 */ 02118 02119 /* 02120 * Using native COMCTL32 gets the following: 02121 * 1 == SHDOCVW.DLL issues call/message 02122 * 2 == COMCTL32.DLL issues call/message 02123 * 3 == WINE issues call/message 02124 * 02125 * 02126 * for LBN_SELCHANGE: 02127 * 1 CB_GETCURSEL(ComboEx) 02128 * 1 CB_GETDROPPEDSTATE(ComboEx) 02129 * 1 CallWindowProc( *2* for WM_COMMAND(LBN_SELCHANGE) 02130 * 2 CallWindowProc( *3* for WM_COMMAND(LBN_SELCHANGE) 02131 ** call CBRollUp( xxx, TRUE for LBN_SELCHANGE, TRUE) 02132 * 3 WM_COMMAND(ComboEx, CBN_SELENDOK) 02133 * WM_USER+49(ComboLB, 1,0) <=============!!!!!!!!!!! 02134 * 3 ShowWindow(ComboLB, SW_HIDE) 02135 * 3 RedrawWindow(Combo, RDW_UPDATENOW) 02136 * 3 WM_COMMAND(ComboEX, CBN_CLOSEUP) 02137 ** end of CBRollUp 02138 * 3 WM_COMMAND(ComboEx, CBN_SELCHANGE) (echo to parent) 02139 * ? LB_GETCURSEL <==| 02140 * ? LB_GETTEXTLEN | 02141 * ? LB_GETTEXT | Needs to be added to 02142 * ? WM_CTLCOLOREDIT(ComboEx) | Combo processing 02143 * ? LB_GETITEMDATA | 02144 * ? WM_DRAWITEM(ComboEx) <==| 02145 */ 02146 default: 02147 break; 02148 }/* fall through */ 02149 default: 02150 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 02151 } 02152 return 0; 02153 } 02154 02155 02156 static LRESULT WINAPI 02157 COMBOEX_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 02158 { 02159 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd); 02160 02161 TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam); 02162 02163 if (!infoPtr) { 02164 if (uMsg == WM_CREATE) 02165 return COMBOEX_Create (hwnd, (LPCREATESTRUCTA)lParam); 02166 if (uMsg == WM_NCCREATE) 02167 COMBOEX_NCCreate (hwnd); 02168 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 02169 } 02170 02171 switch (uMsg) 02172 { 02173 case CBEM_DELETEITEM: 02174 return COMBOEX_DeleteItem (infoPtr, wParam); 02175 02176 case CBEM_GETCOMBOCONTROL: 02177 return (LRESULT)infoPtr->hwndCombo; 02178 02179 case CBEM_GETEDITCONTROL: 02180 return (LRESULT)infoPtr->hwndEdit; 02181 02182 case CBEM_GETEXTENDEDSTYLE: 02183 return infoPtr->dwExtStyle; 02184 02185 case CBEM_GETIMAGELIST: 02186 return (LRESULT)infoPtr->himl; 02187 02188 case CBEM_GETITEMA: 02189 return (LRESULT)COMBOEX_GetItemA (infoPtr, (COMBOBOXEXITEMA *)lParam); 02190 02191 case CBEM_GETITEMW: 02192 return (LRESULT)COMBOEX_GetItemW (infoPtr, (COMBOBOXEXITEMW *)lParam); 02193 02194 case CBEM_GETUNICODEFORMAT: 02195 return infoPtr->unicode; 02196 02197 case CBEM_HASEDITCHANGED: 02198 return COMBOEX_HasEditChanged (infoPtr); 02199 02200 case CBEM_INSERTITEMA: 02201 return COMBOEX_InsertItemA (infoPtr, (COMBOBOXEXITEMA *)lParam); 02202 02203 case CBEM_INSERTITEMW: 02204 return COMBOEX_InsertItemW (infoPtr, (COMBOBOXEXITEMW *)lParam); 02205 02206 case CBEM_SETEXSTYLE: 02207 case CBEM_SETEXTENDEDSTYLE: 02208 return COMBOEX_SetExtendedStyle (infoPtr, (DWORD)wParam, (DWORD)lParam); 02209 02210 case CBEM_SETIMAGELIST: 02211 return (LRESULT)COMBOEX_SetImageList (infoPtr, (HIMAGELIST)lParam); 02212 02213 case CBEM_SETITEMA: 02214 return COMBOEX_SetItemA (infoPtr, (COMBOBOXEXITEMA *)lParam); 02215 02216 case CBEM_SETITEMW: 02217 return COMBOEX_SetItemW (infoPtr, (COMBOBOXEXITEMW *)lParam); 02218 02219 case CBEM_SETUNICODEFORMAT: 02220 return COMBOEX_SetUnicodeFormat (infoPtr, wParam); 02221 02222 /*case CBEM_SETWINDOWTHEME: 02223 FIXME("CBEM_SETWINDOWTHEME: stub\n");*/ 02224 02225 case WM_SETTEXT: 02226 case WM_GETTEXT: 02227 case WM_GETTEXTLENGTH: 02228 return SendMessageW(infoPtr->hwndEdit, uMsg, wParam, lParam); 02229 02230 case CB_GETLBTEXT: 02231 return COMBOEX_GetListboxText(infoPtr, wParam, (LPWSTR)lParam); 02232 02233 case CB_GETLBTEXTLEN: 02234 return COMBOEX_GetListboxText(infoPtr, wParam, NULL); 02235 02236 case CB_RESETCONTENT: 02237 COMBOEX_ResetContent(infoPtr); 02238 /* fall through */ 02239 02240 /* Combo messages we are not sure if we need to process or just forward */ 02241 case CB_GETDROPPEDCONTROLRECT: 02242 case CB_GETITEMHEIGHT: 02243 case CB_GETEXTENDEDUI: 02244 case CB_LIMITTEXT: 02245 case CB_SELECTSTRING: 02246 02247 /* Combo messages OK to just forward to the regular COMBO */ 02248 case CB_GETCOUNT: 02249 case CB_GETCURSEL: 02250 case CB_GETDROPPEDSTATE: 02251 case CB_SETDROPPEDWIDTH: 02252 case CB_SETEXTENDEDUI: 02253 case CB_SHOWDROPDOWN: 02254 return SendMessageW (infoPtr->hwndCombo, uMsg, wParam, lParam); 02255 02256 /* Combo messages we need to process specially */ 02257 case CB_FINDSTRINGEXACT: 02258 return COMBOEX_FindStringExact (infoPtr, (INT)wParam, (LPCWSTR)lParam); 02259 02260 case CB_GETITEMDATA: 02261 return COMBOEX_GetItemData (infoPtr, (INT)wParam); 02262 02263 case CB_SETCURSEL: 02264 return COMBOEX_SetCursel (infoPtr, (INT)wParam); 02265 02266 case CB_SETITEMDATA: 02267 return COMBOEX_SetItemData (infoPtr, (INT)wParam, (DWORD_PTR)lParam); 02268 02269 case CB_SETITEMHEIGHT: 02270 return COMBOEX_SetItemHeight (infoPtr, (INT)wParam, (UINT)lParam); 02271 02272 02273 02274 /* Window messages passed to parent */ 02275 case WM_COMMAND: 02276 return COMBOEX_Command (infoPtr, wParam); 02277 02278 case WM_NOTIFY: 02279 if (infoPtr->NtfUnicode) 02280 return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam); 02281 else 02282 return SendMessageA (infoPtr->hwndNotify, uMsg, wParam, lParam); 02283 02284 02285 /* Window messages we need to process */ 02286 case WM_DELETEITEM: 02287 return COMBOEX_WM_DeleteItem (infoPtr, (DELETEITEMSTRUCT *)lParam); 02288 02289 case WM_DRAWITEM: 02290 return COMBOEX_DrawItem (infoPtr, (DRAWITEMSTRUCT *)lParam); 02291 02292 case WM_DESTROY: 02293 return COMBOEX_Destroy (infoPtr); 02294 02295 case WM_ENABLE: 02296 return COMBOEX_Enable (infoPtr, (BOOL)wParam); 02297 02298 case WM_MEASUREITEM: 02299 return COMBOEX_MeasureItem (infoPtr, (MEASUREITEMSTRUCT *)lParam); 02300 02301 case WM_NOTIFYFORMAT: 02302 return COMBOEX_NotifyFormat (infoPtr, lParam); 02303 02304 case WM_SIZE: 02305 return COMBOEX_Size (infoPtr, LOWORD(lParam), HIWORD(lParam)); 02306 02307 case WM_SETREDRAW: 02308 return COMBOEX_SetRedraw(infoPtr, wParam, lParam); 02309 02310 case WM_WINDOWPOSCHANGING: 02311 return COMBOEX_WindowPosChanging (infoPtr, (WINDOWPOS *)lParam); 02312 02313 case WM_SETFOCUS: 02314 SetFocus(infoPtr->hwndCombo); 02315 return 0; 02316 02317 case WM_SYSCOLORCHANGE: 02318 COMCTL32_RefreshSysColors(); 02319 return 0; 02320 02321 default: 02322 if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg)) 02323 ERR("unknown msg %04x wp=%08lx lp=%08lx\n",uMsg,wParam,lParam); 02324 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 02325 } 02326 } 02327 02328 02329 void COMBOEX_Register (void) 02330 { 02331 WNDCLASSW wndClass; 02332 02333 ZeroMemory (&wndClass, sizeof(WNDCLASSW)); 02334 wndClass.style = CS_GLOBALCLASS; 02335 wndClass.lpfnWndProc = COMBOEX_WindowProc; 02336 wndClass.cbClsExtra = 0; 02337 wndClass.cbWndExtra = sizeof(COMBOEX_INFO *); 02338 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); 02339 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 02340 wndClass.lpszClassName = WC_COMBOBOXEXW; 02341 02342 RegisterClassW (&wndClass); 02343 } 02344 02345 02346 void COMBOEX_Unregister (void) 02347 { 02348 UnregisterClassW (WC_COMBOBOXEXW, NULL); 02349 } Generated on Sun May 27 2012 04:22:58 for ReactOS by
1.7.6.1
|