Release 980927
[wine.git] / controls / combo.c
blob5af3552f4f4c5f3ca0f2e65ce7c51947c8b92504
1 /*
2 * Combo controls
3 *
4 * Copyright 1997 Alex Korobka
5 *
6 * FIXME: roll up in Netscape 3.01.
7 */
9 #include <string.h>
11 #include "windows.h"
12 #include "sysmetrics.h"
13 #include "win.h"
14 #include "spy.h"
15 #include "user.h"
16 #include "graphics.h"
17 #include "heap.h"
18 #include "combo.h"
19 #include "drive.h"
20 #include "debug.h"
22 /* bits in the dwKeyData */
23 #define KEYDATA_ALT 0x2000
24 #define KEYDATA_PREVSTATE 0x4000
27 * Additional combo box definitions
30 #define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra))
31 #define CB_NOTIFY( lphc, code ) \
32 (SendMessage32A( (lphc)->owner, WM_COMMAND, \
33 MAKEWPARAM((lphc)->self->wIDmenu, (code)), (lphc)->self->hwndSelf))
34 #define CB_GETEDITTEXTLENGTH( lphc ) \
35 (SendMessage32A( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
37 static HBITMAP32 hComboBmp = 0;
38 static UINT32 CBitHeight, CBitWidth;
39 static UINT32 CBitOffset = 8;
41 /***********************************************************************
42 * COMBO_Init
44 * Load combo button bitmap.
46 static BOOL32 COMBO_Init()
48 HDC32 hDC;
50 if( hComboBmp ) return TRUE;
51 if( (hDC = CreateCompatibleDC32(0)) )
53 BOOL32 bRet = FALSE;
54 if( (hComboBmp = LoadBitmap32A(0, MAKEINTRESOURCE32A(OBM_COMBO))) )
56 BITMAP32 bm;
57 HBITMAP32 hPrevB;
58 RECT32 r;
60 GetObject32A( hComboBmp, sizeof(bm), &bm );
61 CBitHeight = bm.bmHeight;
62 CBitWidth = bm.bmWidth;
64 TRACE(combo, "combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
66 hPrevB = SelectObject16( hDC, hComboBmp);
67 SetRect32( &r, 0, 0, CBitWidth, CBitHeight );
68 InvertRect32( hDC, &r );
69 SelectObject32( hDC, hPrevB );
70 bRet = TRUE;
72 DeleteDC32( hDC );
73 return bRet;
75 return FALSE;
78 /***********************************************************************
79 * COMBO_NCCreate
81 static LRESULT COMBO_NCCreate(WND* wnd, LPARAM lParam)
83 LPHEADCOMBO lphc;
85 if ( wnd && COMBO_Init() &&
86 (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) )
88 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
90 memset( lphc, 0, sizeof(HEADCOMBO) );
91 *(LPHEADCOMBO*)wnd->wExtra = lphc;
93 /* some braindead apps do try to use scrollbar/border flags */
95 lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL));
96 wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
98 if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
99 lphc->dwStyle |= CBS_HASSTRINGS;
100 if( !(wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) )
101 lphc->wState |= CBF_NOTIFY;
103 TRACE(combo, "[0x%08x], style = %08x\n",
104 (UINT32)lphc, lphc->dwStyle );
106 return (LRESULT)(UINT32)wnd->hwndSelf;
108 return (LRESULT)FALSE;
111 /***********************************************************************
112 * COMBO_NCDestroy
114 static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc )
117 if( lphc )
119 WND* wnd = lphc->self;
121 TRACE(combo,"[%04x]: freeing storage\n", CB_HWND(lphc));
123 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
124 DestroyWindow32( lphc->hWndLBox );
126 HeapFree( GetProcessHeap(), 0, lphc );
127 wnd->wExtra[0] = 0;
129 return 0;
133 /***********************************************************************
134 * CBCalcPlacement
136 * Set up component coordinates given valid lphc->RectCombo.
138 static void CBCalcPlacement( LPHEADCOMBO lphc, LPRECT32 lprEdit,
139 LPRECT32 lprButton, LPRECT32 lprLB )
141 RECT32 rect = lphc->RectCombo;
142 SIZE32 size;
144 /* get combo height and width */
146 size.cx = rect.right - rect.left;
148 if( CB_OWNERDRAWN(lphc) )
150 UINT32 u = lphc->RectEdit.bottom - lphc->RectEdit.top;
152 if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */
154 MEASUREITEMSTRUCT32 mi32;
156 lphc->wState &= ~CBF_MEASUREITEM;
157 mi32.CtlType = ODT_COMBOBOX;
158 mi32.CtlID = lphc->self->wIDmenu;
159 mi32.itemID = -1;
160 mi32.itemWidth = size.cx;
161 mi32.itemHeight = u - 6; /* ownerdrawn cb is taller */
162 mi32.itemData = 0;
163 SendMessage32A(lphc->owner, WM_MEASUREITEM,
164 (WPARAM32)mi32.CtlID, (LPARAM)&mi32);
165 u = 6 + (UINT16)mi32.itemHeight;
167 size.cy = u;
169 else if( lphc->editHeight ) /* explicitly set height */
170 size.cy = lphc->editHeight;
171 else
173 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
174 HFONT32 hPrevFont = 0;
175 SIZE32 font_size;
177 if( lphc->hFont ) hPrevFont = SelectObject32( hDC, lphc->hFont );
179 GetTextExtentPoint32A( hDC, "0", 1, &font_size);
181 size.cy = font_size.cy + font_size.cy / 4 + 4 * SYSMETRICS_CYBORDER;
183 if( hPrevFont ) SelectObject32( hDC, hPrevFont );
184 ReleaseDC32( lphc->self->hwndSelf, hDC );
188 /* calculate text and button placement */
190 lprEdit->left = lprEdit->top = lprButton->top = 0;
191 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* no button */
192 lprButton->left = lprButton->right = lprButton->bottom = 0;
193 else
195 INT32 i = size.cx - CBitWidth - 10; /* seems ok */
197 lprButton->right = size.cx;
198 lprButton->left = (INT16)i;
199 lprButton->bottom = lprButton->top + size.cy;
201 if( i < 0 ) size.cx = 0;
202 else size.cx = i;
205 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
207 size.cx -= CBitOffset;
208 if( size.cx < 0 ) size.cx = 0;
211 lprEdit->right = size.cx; lprEdit->bottom = size.cy;
213 /* listbox placement */
215 lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
216 lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER;
217 lprLB->right = rect.right - rect.left;
218 lprLB->bottom = rect.bottom - rect.top;
220 if( lphc->droppedWidth > (lprLB->right - lprLB->left) )
221 lprLB->right = lprLB->left + lphc->droppedWidth;
223 TRACE(combo,"[%04x]: (%i,%i-%i,%i) placement\n",
224 CB_HWND(lphc), lphc->RectCombo.left, lphc->RectCombo.top,
225 lphc->RectCombo.right, lphc->RectCombo.bottom);
227 TRACE(combo,"\ttext\t= (%i,%i-%i,%i)\n",
228 lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
230 TRACE(combo,"\tbutton\t= (%i,%i-%i,%i)\n",
231 lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
233 TRACE(combo,"\tlbox\t= (%i,%i-%i,%i)\n",
234 lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
237 /***********************************************************************
238 * CBGetDroppedControlRect32
240 static void CBGetDroppedControlRect32( LPHEADCOMBO lphc, LPRECT32 lpRect)
242 lpRect->left = lphc->RectCombo.left +
243 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
244 lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom -
245 SYSMETRICS_CYBORDER;
246 lpRect->right = lphc->RectCombo.right;
247 lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER;
250 /***********************************************************************
251 * COMBO_Create
253 static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
255 static char clbName[] = "ComboLBox";
256 static char editName[] = "Edit";
258 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
260 if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
261 else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
263 lphc->self = wnd;
264 lphc->owner = lpcs->hwndParent;
266 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
268 if( lphc->owner || !(lpcs->style & WS_VISIBLE) )
270 UINT32 lbeStyle;
271 RECT32 editRect, btnRect, lbRect;
273 GetWindowRect32( wnd->hwndSelf, &lphc->RectCombo );
275 lphc->wState |= CBF_MEASUREITEM;
276 CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect );
277 lphc->RectButton = btnRect;
278 lphc->droppedWidth = lphc->editHeight = 0;
280 /* create listbox popup */
282 lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) |
283 (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
285 if( lphc->dwStyle & CBS_SORT )
286 lbeStyle |= LBS_SORT;
287 if( lphc->dwStyle & CBS_HASSTRINGS )
288 lbeStyle |= LBS_HASSTRINGS;
289 if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
290 lbeStyle |= LBS_NOINTEGRALHEIGHT;
291 if( lphc->dwStyle & CBS_DISABLENOSCROLL )
292 lbeStyle |= LBS_DISABLENOSCROLL;
294 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */
295 lbeStyle |= WS_CHILD | WS_VISIBLE;
296 else /* popup listbox */
298 lbeStyle |= WS_POPUP;
299 OffsetRect32( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
302 /* Dropdown ComboLBox is not a child window and we cannot pass
303 * ID_CB_LISTBOX directly because it will be treated as a menu handle.
306 lphc->hWndLBox = CreateWindowEx32A( 0, clbName, NULL, lbeStyle,
307 lbRect.left + SYSMETRICS_CXBORDER,
308 lbRect.top + SYSMETRICS_CYBORDER,
309 lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER,
310 lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER,
311 lphc->self->hwndSelf,
312 (lphc->dwStyle & CBS_DROPDOWN)? (HMENU32)0 : (HMENU32)ID_CB_LISTBOX,
313 lphc->self->hInstance, (LPVOID)lphc );
314 if( lphc->hWndLBox )
316 BOOL32 bEdit = TRUE;
317 lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT;
318 if( lphc->wState & CBF_EDIT )
320 if( lphc->dwStyle & CBS_OEMCONVERT )
321 lbeStyle |= ES_OEMCONVERT;
322 if( lphc->dwStyle & CBS_AUTOHSCROLL )
323 lbeStyle |= ES_AUTOHSCROLL;
324 if( lphc->dwStyle & CBS_LOWERCASE )
325 lbeStyle |= ES_LOWERCASE;
326 else if( lphc->dwStyle & CBS_UPPERCASE )
327 lbeStyle |= ES_UPPERCASE;
328 lphc->hWndEdit = CreateWindowEx32A( 0, editName, NULL, lbeStyle,
329 editRect.left, editRect.top, editRect.right - editRect.left,
330 editRect.bottom - editRect.top, lphc->self->hwndSelf,
331 (HMENU32)ID_CB_EDIT, lphc->self->hInstance, NULL );
332 if( !lphc->hWndEdit ) bEdit = FALSE;
335 if( bEdit )
337 lphc->RectEdit = editRect;
338 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
340 lphc->wState |= CBF_NORESIZE;
341 SetWindowPos32( wnd->hwndSelf, 0, 0, 0,
342 lphc->RectCombo.right - lphc->RectCombo.left,
343 lphc->RectEdit.bottom - lphc->RectEdit.top,
344 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
345 lphc->wState &= ~CBF_NORESIZE;
347 TRACE(combo,"init done\n");
348 return wnd->hwndSelf;
350 ERR(combo, "edit control failure.\n");
351 } else ERR(combo, "listbox failure.\n");
352 } else ERR(combo, "no owner for visible combo.\n");
354 /* CreateWindow() will send WM_NCDESTROY to cleanup */
356 return -1;
359 /***********************************************************************
360 * CBPaintButton
362 * Paint combo button (normal, pressed, and disabled states).
364 static void CBPaintButton(LPHEADCOMBO lphc, HDC32 hdc)
366 RECT32 r;
367 HBRUSH32 hPrevBrush;
368 UINT32 x, y;
369 BOOL32 bBool;
371 if( lphc->wState & CBF_NOREDRAW ) return;
373 hPrevBrush = (HBRUSH32)SelectObject32(hdc, GetSysColorBrush32(COLOR_BTNFACE));
374 CONV_RECT16TO32( &lphc->RectButton, &r );
376 Rectangle32(hdc, r.left, r.top, r.right, r.bottom );
377 InflateRect32( &r, -1, -1 );
378 if( (bBool = lphc->wState & CBF_BUTTONDOWN) )
380 GRAPH_DrawReliefRect(hdc, &r, 1, 0, TRUE);
381 OffsetRect32( &r, 1, 1 );
382 } else GRAPH_DrawReliefRect(hdc, &r, 1, 2, FALSE);
384 x = (r.left + r.right - CBitWidth) >> 1;
385 y = (r.top + r.bottom - CBitHeight) >> 1;
387 InflateRect32( &r, -3, -3 );
388 if( (bBool = CB_DISABLED(lphc)) )
390 GRAPH_SelectClipMask(hdc, hComboBmp, x + 1, y + 1 );
391 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32(WHITE_BRUSH));
394 GRAPH_SelectClipMask(hdc, hComboBmp, x, y );
395 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32((bBool) ? GRAY_BRUSH : BLACK_BRUSH));
397 GRAPH_SelectClipMask(hdc, (HBITMAP32)0, 0, 0);
398 SelectObject32( hdc, hPrevBrush );
401 /***********************************************************************
402 * CBPaintText
404 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
406 static void CBPaintText(LPHEADCOMBO lphc, HDC32 hdc)
408 INT32 id, size = 0;
409 LPSTR pText = NULL;
411 if( lphc->wState & CBF_NOREDRAW ) return;
413 /* follow Windows combobox that sends a bunch of text
414 * inquiries to its listbox while processing WM_PAINT. */
416 if( (id = SendMessage32A(lphc->hWndLBox, LB_GETCURSEL32, 0, 0) ) != LB_ERR )
418 size = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, id, 0);
419 if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) )
421 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, (WPARAM32)id, (LPARAM)pText );
422 pText[size] = '\0'; /* just in case */
423 } else return;
426 if( lphc->wState & CBF_EDIT )
428 if( CB_HASSTRINGS(lphc) ) SetWindowText32A( lphc->hWndEdit, pText );
429 if( lphc->wState & CBF_FOCUSED )
430 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1));
432 else /* paint text field ourselves */
434 HBRUSH32 hPrevBrush = 0;
435 HDC32 hDC = hdc;
437 if( !hDC )
439 if ((hDC = GetDC32(lphc->self->hwndSelf)))
441 HBRUSH32 hBrush = SendMessage32A( lphc->owner,
442 WM_CTLCOLORLISTBOX,
443 hDC, lphc->self->hwndSelf );
444 hPrevBrush = SelectObject32( hDC,
445 (hBrush) ? hBrush : GetStockObject32(WHITE_BRUSH) );
448 if( hDC )
450 RECT32 rect;
451 UINT32 itemState;
452 HFONT32 hPrevFont = (lphc->hFont) ? SelectObject32(hDC, lphc->hFont) : 0;
454 PatBlt32( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER),
455 (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER),
456 (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER),
457 (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY );
458 InflateRect32( &rect, -1, -1 );
460 if( lphc->wState & CBF_FOCUSED &&
461 !(lphc->wState & CBF_DROPPED) )
463 /* highlight */
465 FillRect32( hDC, &rect, GetSysColorBrush32(COLOR_HIGHLIGHT) );
466 SetBkColor32( hDC, GetSysColor32( COLOR_HIGHLIGHT ) );
467 SetTextColor32( hDC, GetSysColor32( COLOR_HIGHLIGHTTEXT ) );
468 itemState = ODS_SELECTED | ODS_FOCUS;
469 } else itemState = 0;
471 if( CB_OWNERDRAWN(lphc) )
473 DRAWITEMSTRUCT32 dis;
475 if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED;
477 dis.CtlType = ODT_COMBOBOX;
478 dis.CtlID = lphc->self->wIDmenu;
479 dis.hwndItem = lphc->self->hwndSelf;
480 dis.itemAction = ODA_DRAWENTIRE;
481 dis.itemID = id;
482 dis.itemState = itemState;
483 dis.hDC = hDC;
484 dis.rcItem = rect;
485 dis.itemData = SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32,
486 (WPARAM32)id, 0 );
487 SendMessage32A( lphc->owner, WM_DRAWITEM,
488 lphc->self->wIDmenu, (LPARAM)&dis );
490 else
492 ExtTextOut32A( hDC, rect.left + 1, rect.top + 1,
493 ETO_OPAQUE | ETO_CLIPPED, &rect,
494 (pText) ? pText : "" , size, NULL );
495 if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
496 DrawFocusRect32( hDC, &rect );
499 if( hPrevFont ) SelectObject32(hDC, hPrevFont );
500 if( !hdc )
502 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
503 ReleaseDC32( lphc->self->hwndSelf, hDC );
507 HeapFree( GetProcessHeap(), 0, pText );
510 /***********************************************************************
511 * COMBO_Paint
513 static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC32 hParamDC)
515 PAINTSTRUCT32 ps;
516 HDC32 hDC;
518 hDC = (hParamDC) ? hParamDC
519 : BeginPaint32( lphc->self->hwndSelf, &ps);
520 if( hDC && !(lphc->wState & CBF_NOREDRAW) )
522 HBRUSH32 hPrevBrush, hBkgBrush;
524 hBkgBrush = SendMessage32A( lphc->owner, WM_CTLCOLORLISTBOX,
525 hDC, lphc->self->hwndSelf );
526 if( !hBkgBrush ) hBkgBrush = GetStockObject32(WHITE_BRUSH);
528 hPrevBrush = SelectObject32( hDC, hBkgBrush );
529 if( !IsRectEmpty32(&lphc->RectButton) )
531 /* paint everything to the right of the text field */
533 PatBlt32( hDC, lphc->RectEdit.right, lphc->RectEdit.top,
534 lphc->RectButton.right - lphc->RectEdit.right,
535 lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY );
536 CBPaintButton( lphc, hDC );
539 if( !(lphc->wState & CBF_EDIT) )
541 /* paint text field */
543 GRAPH_DrawRectangle( hDC, lphc->RectEdit.left, lphc->RectEdit.top,
544 lphc->RectEdit.right - lphc->RectEdit.left,
545 lphc->RectButton.bottom - lphc->RectButton.top,
546 GetSysColorPen32(COLOR_WINDOWFRAME) );
547 CBPaintText( lphc, hDC );
549 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
551 if( !hParamDC ) EndPaint32(lphc->self->hwndSelf, &ps);
552 return 0;
555 /***********************************************************************
556 * CBUpdateLBox
558 * Select listbox entry according to the contents of the edit control.
560 static INT32 CBUpdateLBox( LPHEADCOMBO lphc )
562 INT32 length, idx, ret;
563 LPSTR pText = NULL;
565 idx = ret = LB_ERR;
566 length = CB_GETEDITTEXTLENGTH( lphc );
568 if( length > 0 )
569 pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
571 TRACE(combo,"\t edit text length %i\n", length );
573 if( pText )
575 if( length ) GetWindowText32A( lphc->hWndEdit, pText, length + 1);
576 else pText[0] = '\0';
577 idx = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
578 (WPARAM32)(-1), (LPARAM)pText );
579 if( idx == LB_ERR ) idx = 0; /* select first item */
580 else ret = idx;
581 HeapFree( GetProcessHeap(), 0, pText );
584 /* select entry */
586 SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, (WPARAM32)idx, 0 );
588 if( idx >= 0 )
590 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)idx, 0 );
591 /* probably superfluous but Windows sends this too */
592 SendMessage32A( lphc->hWndLBox, LB_SETCARETINDEX32, (WPARAM32)idx, 0 );
594 return ret;
597 /***********************************************************************
598 * CBUpdateEdit
600 * Copy a listbox entry to the edit control.
602 static void CBUpdateEdit( LPHEADCOMBO lphc , INT32 index )
604 INT32 length;
605 LPSTR pText = NULL;
607 TRACE(combo,"\t %i\n", index );
609 if( index == -1 )
611 length = CB_GETEDITTEXTLENGTH( lphc );
612 if( length )
614 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
616 GetWindowText32A( lphc->hWndEdit, pText, length + 1 );
617 index = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
618 (WPARAM32)(-1), (LPARAM)pText );
619 HeapFree( GetProcessHeap(), 0, pText );
624 if( index >= 0 ) /* got an entry */
626 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, (WPARAM32)index, 0);
627 if( length )
629 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
631 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
632 (WPARAM32)index, (LPARAM)pText );
633 SendMessage32A( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText );
634 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
635 HeapFree( GetProcessHeap(), 0, pText );
641 /***********************************************************************
642 * CBDropDown
644 * Show listbox popup.
646 static void CBDropDown( LPHEADCOMBO lphc )
648 INT32 index;
649 RECT32 rect;
650 LPRECT32 pRect = NULL;
652 TRACE(combo,"[%04x]: drop down\n", CB_HWND(lphc));
654 CB_NOTIFY( lphc, CBN_DROPDOWN );
656 /* set selection */
658 lphc->wState |= CBF_DROPPED;
659 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
661 index = CBUpdateLBox( lphc );
662 if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index );
664 else
666 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
667 if( index == LB_ERR ) index = 0;
668 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)index, 0 );
669 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
670 pRect = &lphc->RectEdit;
673 /* now set popup position */
675 GetWindowRect32( lphc->self->hwndSelf, &rect );
677 rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER;
678 rect.bottom = rect.top + lphc->RectCombo.bottom -
679 lphc->RectCombo.top - SYSMETRICS_CYBORDER;
680 rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left;
681 rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
683 SetWindowPos32( lphc->hWndLBox, HWND_TOP, rect.left, rect.top,
684 rect.right - rect.left, rect.bottom - rect.top,
685 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW);
687 if( !(lphc->wState & CBF_NOREDRAW) )
688 if( pRect )
689 RedrawWindow32( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE |
690 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
691 ShowWindow32( lphc->hWndLBox, SW_SHOWNA );
694 /***********************************************************************
695 * CBRollUp
697 * Hide listbox popup.
699 static void CBRollUp( LPHEADCOMBO lphc, BOOL32 ok, BOOL32 bButton )
701 HWND32 hWnd = lphc->self->hwndSelf;
703 CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
705 if( IsWindow32( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
708 TRACE(combo,"[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT32)ok );
710 /* always send WM_LBUTTONUP? */
711 SendMessage32A( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) );
713 if( lphc->wState & CBF_DROPPED )
715 RECT32 rect;
717 lphc->wState &= ~CBF_DROPPED;
718 ShowWindow32( lphc->hWndLBox, SW_HIDE );
720 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
722 INT32 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
723 CBUpdateEdit( lphc, index );
724 rect = lphc->RectButton;
726 else
728 if( bButton )
729 UnionRect32( &rect, &lphc->RectButton,
730 &lphc->RectEdit );
731 else
732 rect = lphc->RectEdit;
733 bButton = TRUE;
736 if( bButton && !(lphc->wState & CBF_NOREDRAW) )
737 RedrawWindow32( hWnd, &rect, 0, RDW_INVALIDATE |
738 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
739 CB_NOTIFY( lphc, CBN_CLOSEUP );
744 /***********************************************************************
745 * COMBO_FlipListbox
747 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
749 BOOL32 COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL32 bRedrawButton )
751 if( lphc->wState & CBF_DROPPED )
753 CBRollUp( lphc, TRUE, bRedrawButton );
754 return FALSE;
757 CBDropDown( lphc );
758 return TRUE;
761 /***********************************************************************
762 * COMBO_GetLBWindow
764 * Edit control helper.
766 HWND32 COMBO_GetLBWindow( WND* pWnd )
768 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
769 if( lphc ) return lphc->hWndLBox;
770 return 0;
774 /***********************************************************************
775 * CBRepaintButton
777 static void CBRepaintButton( LPHEADCOMBO lphc )
779 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
781 if( hDC )
783 CBPaintButton( lphc, hDC );
784 ReleaseDC32( lphc->self->hwndSelf, hDC );
788 /***********************************************************************
789 * COMBO_SetFocus
791 static void COMBO_SetFocus( LPHEADCOMBO lphc )
793 if( !(lphc->wState & CBF_FOCUSED) )
795 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
796 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
798 if( lphc->wState & CBF_EDIT )
799 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
800 lphc->wState |= CBF_FOCUSED;
801 if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 0 );
803 CB_NOTIFY( lphc, CBN_SETFOCUS );
807 /***********************************************************************
808 * COMBO_KillFocus
810 static void COMBO_KillFocus( LPHEADCOMBO lphc )
812 HWND32 hWnd = lphc->self->hwndSelf;
814 if( lphc->wState & CBF_FOCUSED )
816 SendMessage32A( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) );
818 CBRollUp( lphc, FALSE, TRUE );
819 if( IsWindow32( hWnd ) )
821 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
822 SendMessage32A( lphc->hWndLBox, LB_CARETOFF32, 0, 0 );
824 lphc->wState &= ~CBF_FOCUSED;
826 /* redraw text */
827 if( lphc->wState & CBF_EDIT )
828 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, (WPARAM32)(-1), 0 );
829 else CBPaintText( lphc, 0 );
831 CB_NOTIFY( lphc, CBN_KILLFOCUS );
836 /***********************************************************************
837 * COMBO_Command
839 static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM32 wParam, HWND32 hWnd )
841 if( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
843 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
845 switch( HIWORD(wParam) >> 8 )
847 case (EN_SETFOCUS >> 8):
849 TRACE(combo,"[%04x]: edit [%04x] got focus\n",
850 CB_HWND(lphc), lphc->hWndEdit );
852 if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc );
853 break;
855 case (EN_KILLFOCUS >> 8):
857 TRACE(combo,"[%04x]: edit [%04x] lost focus\n",
858 CB_HWND(lphc), lphc->hWndEdit );
860 /* NOTE: it seems that Windows' edit control sends an
861 * undocumented message WM_USER + 0x1B instead of this
862 * notification (only when it happens to be a part of
863 * the combo). ?? - AK.
866 COMBO_KillFocus( lphc );
867 break;
870 case (EN_CHANGE >> 8):
871 CB_NOTIFY( lphc, CBN_EDITCHANGE );
872 CBUpdateLBox( lphc );
873 break;
875 case (EN_UPDATE >> 8):
876 CB_NOTIFY( lphc, CBN_EDITUPDATE );
877 break;
879 case (EN_ERRSPACE >> 8):
880 CB_NOTIFY( lphc, CBN_ERRSPACE );
883 else if( lphc->hWndLBox == hWnd )
885 switch( HIWORD(wParam) )
887 case LBN_ERRSPACE:
888 CB_NOTIFY( lphc, CBN_ERRSPACE );
889 break;
891 case LBN_DBLCLK:
892 CB_NOTIFY( lphc, CBN_DBLCLK );
893 break;
895 case LBN_SELCHANGE:
896 case LBN_SELCANCEL:
898 TRACE(combo,"[%04x]: lbox selection change [%04x]\n",
899 CB_HWND(lphc), lphc->wState );
901 /* do not roll up if selection is being tracked
902 * by arrowkeys in the dropdown listbox */
904 if( (lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP) )
905 CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
906 else lphc->wState &= ~CBF_NOROLLUP;
908 CB_NOTIFY( lphc, CBN_SELCHANGE );
909 CBPaintText( lphc, 0 );
910 /* fall through */
912 case LBN_SETFOCUS:
913 case LBN_KILLFOCUS:
914 /* nothing to do here since ComboLBox always resets the focus to its
915 * combo/edit counterpart */
916 break;
919 return 0;
922 /***********************************************************************
923 * COMBO_ItemOp
925 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
927 static LRESULT COMBO_ItemOp32( LPHEADCOMBO lphc, UINT32 msg,
928 WPARAM32 wParam, LPARAM lParam )
930 HWND32 hWnd = lphc->self->hwndSelf;
932 TRACE(combo,"[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg );
934 #define lpIS ((LPDELETEITEMSTRUCT32)lParam)
936 /* two first items are the same in all 4 structs */
937 lpIS->CtlType = ODT_COMBOBOX;
938 lpIS->CtlID = lphc->self->wIDmenu;
940 switch( msg ) /* patch window handle */
942 case WM_DELETEITEM:
943 lpIS->hwndItem = hWnd;
944 #undef lpIS
945 break;
946 case WM_DRAWITEM:
947 #define lpIS ((LPDRAWITEMSTRUCT32)lParam)
948 lpIS->hwndItem = hWnd;
949 #undef lpIS
950 break;
951 case WM_COMPAREITEM:
952 #define lpIS ((LPCOMPAREITEMSTRUCT32)lParam)
953 lpIS->hwndItem = hWnd;
954 #undef lpIS
955 break;
958 return SendMessage32A( lphc->owner, msg, lphc->self->wIDmenu, lParam );
961 /***********************************************************************
962 * COMBO_GetText
964 static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT32 N, LPSTR lpText)
966 if( lphc->wState & CBF_EDIT )
967 return SendMessage32A( lphc->hWndEdit, WM_GETTEXT,
968 (WPARAM32)N, (LPARAM)lpText );
970 /* get it from the listbox */
972 if( lphc->hWndLBox )
974 INT32 idx = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
975 if( idx != LB_ERR )
977 LPSTR lpBuffer;
978 INT32 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32,
979 (WPARAM32)idx, 0 );
981 /* 'length' is without the terminating character */
982 if( length >= N )
983 lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
984 else
985 lpBuffer = lpText;
987 if( lpBuffer )
989 INT32 n = SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
990 (WPARAM32)idx, (LPARAM)lpText );
992 /* truncate if buffer is too short */
994 if( length >= N )
996 if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
997 lpText[N - 1] = '\0';
998 HeapFree( GetProcessHeap(), 0, lpBuffer );
1000 return (LRESULT)n;
1004 return 0;
1008 /***********************************************************************
1009 * CBResetPos
1011 * This function sets window positions according to the updated
1012 * component placement struct.
1014 static void CBResetPos( LPHEADCOMBO lphc, LPRECT32 lbRect, BOOL32 bRedraw )
1016 BOOL32 bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
1018 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1019 * sizing messages */
1021 if( lphc->wState & CBF_EDIT )
1022 SetWindowPos32( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top,
1023 lphc->RectEdit.right - lphc->RectEdit.left,
1024 lphc->RectEdit.bottom - lphc->RectEdit.top,
1025 SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
1027 if( bDrop )
1028 OffsetRect32( lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
1030 lbRect->right -= lbRect->left; /* convert to width */
1031 lbRect->bottom -= lbRect->top;
1032 SetWindowPos32( lphc->hWndLBox, 0, lbRect->left, lbRect->top,
1033 lbRect->right, lbRect->bottom,
1034 SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
1036 if( bDrop )
1038 if( lphc->wState & CBF_DROPPED )
1040 lphc->wState &= ~CBF_DROPPED;
1041 ShowWindow32( lphc->hWndLBox, SW_HIDE );
1044 lphc->wState |= CBF_NORESIZE;
1045 SetWindowPos32( lphc->self->hwndSelf, 0, 0, 0,
1046 lphc->RectCombo.right - lphc->RectCombo.left,
1047 lphc->RectEdit.bottom - lphc->RectEdit.top,
1048 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
1049 lphc->wState &= ~CBF_NORESIZE;
1051 if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
1052 RedrawWindow32( lphc->self->hwndSelf, NULL, 0,
1053 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
1058 /***********************************************************************
1059 * COMBO_Size
1061 static void COMBO_Size( LPHEADCOMBO lphc )
1063 RECT32 rect;
1064 INT32 w, h;
1066 GetWindowRect32( lphc->self->hwndSelf, &rect );
1067 w = rect.right - rect.left; h = rect.bottom - rect.top;
1069 TRACE(combo,"w = %i, h = %i\n", w, h );
1071 /* CreateWindow() may send a bogus WM_SIZE, ignore it */
1073 if( w == (lphc->RectCombo.right - lphc->RectCombo.left) ) {
1074 if( (CB_GETTYPE(lphc) == CBS_SIMPLE) &&
1075 (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) )
1076 return;
1077 else if( (lphc->dwStyle & CBS_DROPDOWN) &&
1078 (h == (lphc->RectEdit.bottom - lphc->RectEdit.top)) )
1079 return;
1082 lphc->RectCombo = rect;
1083 CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect );
1084 CBResetPos( lphc, &rect, TRUE );
1088 /***********************************************************************
1089 * COMBO_Font
1091 static void COMBO_Font( LPHEADCOMBO lphc, HFONT32 hFont, BOOL32 bRedraw )
1093 RECT32 rect;
1095 lphc->hFont = hFont;
1097 if( lphc->wState & CBF_EDIT )
1098 SendMessage32A( lphc->hWndEdit, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1099 SendMessage32A( lphc->hWndLBox, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1101 GetWindowRect32( lphc->self->hwndSelf, &rect );
1102 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1103 rect.top - lphc->RectCombo.top );
1104 CBCalcPlacement( lphc, &lphc->RectEdit,
1105 &lphc->RectButton, &rect );
1106 CBResetPos( lphc, &rect, bRedraw );
1110 /***********************************************************************
1111 * COMBO_SetItemHeight
1113 static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT32 index, INT32 height )
1115 LRESULT lRet = CB_ERR;
1117 if( index == -1 ) /* set text field height */
1119 if( height < 32768 )
1121 RECT32 rect;
1123 lphc->editHeight = height;
1124 GetWindowRect32( lphc->self->hwndSelf, &rect );
1125 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1126 rect.top - lphc->RectCombo.top );
1127 CBCalcPlacement( lphc, &lphc->RectEdit,
1128 &lphc->RectButton, &rect );
1129 CBResetPos( lphc, &rect, TRUE );
1130 lRet = height;
1133 else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
1134 lRet = SendMessage32A( lphc->hWndLBox, LB_SETITEMHEIGHT32,
1135 (WPARAM32)index, (LPARAM)height );
1136 return lRet;
1139 /***********************************************************************
1140 * COMBO_SelectString
1142 static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT32 start, LPCSTR pText )
1144 INT32 index = SendMessage32A( lphc->hWndLBox, LB_SELECTSTRING32,
1145 (WPARAM32)start, (LPARAM)pText );
1146 if( index >= 0 ) {
1147 if( lphc->wState & CBF_EDIT )
1148 CBUpdateEdit( lphc, index );
1149 else
1150 CBPaintText( lphc, 0 );
1152 return (LRESULT)index;
1155 /***********************************************************************
1156 * COMBO_LButtonDown
1158 static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
1160 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1161 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1162 HWND32 hWnd = lphc->self->hwndSelf;
1164 if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
1165 (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
1167 lphc->wState |= CBF_BUTTONDOWN;
1168 if( lphc->wState & CBF_DROPPED )
1170 /* got a click to cancel selection */
1172 CBRollUp( lphc, TRUE, FALSE );
1173 if( !IsWindow32( hWnd ) ) return;
1175 if( lphc->wState & CBF_CAPTURE )
1177 lphc->wState &= ~CBF_CAPTURE;
1178 ReleaseCapture();
1180 lphc->wState &= ~CBF_BUTTONDOWN;
1182 else
1184 /* drop down the listbox and start tracking */
1186 lphc->wState |= CBF_CAPTURE;
1187 CBDropDown( lphc );
1188 SetCapture32( hWnd );
1190 if( bButton ) CBRepaintButton( lphc );
1194 /***********************************************************************
1195 * COMBO_LButtonUp
1197 * Release capture and stop tracking if needed.
1199 static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
1201 if( lphc->wState & CBF_CAPTURE )
1203 lphc->wState &= ~CBF_CAPTURE;
1204 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1206 INT32 index = CBUpdateLBox( lphc );
1207 CBUpdateEdit( lphc, index );
1209 ReleaseCapture();
1212 if( lphc->wState & CBF_BUTTONDOWN )
1214 lphc->wState &= ~CBF_BUTTONDOWN;
1215 CBRepaintButton( lphc );
1219 /***********************************************************************
1220 * COMBO_MouseMove
1222 * Two things to do - track combo button and release capture when
1223 * pointer goes into the listbox.
1225 static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM32 wParam, LPARAM lParam )
1227 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1228 RECT32 lbRect;
1230 if( lphc->wState & CBF_BUTTONDOWN )
1232 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1234 if( !bButton )
1236 lphc->wState &= ~CBF_BUTTONDOWN;
1237 CBRepaintButton( lphc );
1241 GetClientRect32( lphc->hWndLBox, &lbRect );
1242 MapWindowPoints32( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 );
1243 if( PtInRect32(&lbRect, pt) )
1245 lphc->wState &= ~CBF_CAPTURE;
1246 ReleaseCapture();
1247 if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
1249 /* hand over pointer tracking */
1250 SendMessage32A( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
1255 /***********************************************************************
1256 * ComboWndProc
1258 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1260 LRESULT WINAPI ComboWndProc( HWND32 hwnd, UINT32 message,
1261 WPARAM32 wParam, LPARAM lParam )
1263 WND* pWnd = WIN_FindWndPtr(hwnd);
1265 if( pWnd )
1267 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
1269 TRACE(combo, "[%04x]: msg %s wp %08x lp %08lx\n",
1270 pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
1272 if( lphc || message == WM_NCCREATE )
1273 switch(message)
1276 /* System messages */
1278 case WM_NCCREATE:
1279 return COMBO_NCCreate(pWnd, lParam);
1281 case WM_NCDESTROY:
1282 COMBO_NCDestroy(lphc);
1283 break;
1285 case WM_CREATE:
1286 return COMBO_Create(lphc, pWnd, lParam);
1288 case WM_PAINT:
1289 /* wParam may contain a valid HDC! */
1290 return COMBO_Paint(lphc, wParam);
1292 case WM_ERASEBKGND:
1293 return TRUE;
1295 case WM_GETDLGCODE:
1296 return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
1298 case WM_SIZE:
1299 if( lphc->hWndLBox &&
1300 !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
1301 return TRUE;
1303 case WM_SETFONT:
1304 COMBO_Font( lphc, (HFONT16)wParam, (BOOL32)lParam );
1305 return TRUE;
1307 case WM_GETFONT:
1308 return (LRESULT)lphc->hFont;
1310 case WM_SETFOCUS:
1311 if( lphc->wState & CBF_EDIT )
1312 SetFocus32( lphc->hWndEdit );
1313 else
1314 COMBO_SetFocus( lphc );
1315 return TRUE;
1317 case WM_KILLFOCUS:
1318 #define hwndFocus ((HWND16)wParam)
1319 if( !hwndFocus ||
1320 (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
1321 COMBO_KillFocus( lphc );
1322 #undef hwndFocus
1323 return TRUE;
1325 case WM_COMMAND:
1326 return COMBO_Command( lphc, wParam, (HWND32)lParam );
1328 case WM_GETTEXT:
1329 return COMBO_GetText( lphc, (UINT32)wParam, (LPSTR)lParam );
1331 case WM_SETTEXT:
1332 case WM_GETTEXTLENGTH:
1333 case WM_CLEAR:
1334 case WM_CUT:
1335 case WM_PASTE:
1336 case WM_COPY:
1337 if( lphc->wState & CBF_EDIT )
1338 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1339 return CB_ERR;
1341 case WM_DRAWITEM:
1342 case WM_DELETEITEM:
1343 case WM_COMPAREITEM:
1344 case WM_MEASUREITEM:
1345 return COMBO_ItemOp32( lphc, message, wParam, lParam );
1347 case WM_ENABLE:
1348 if( lphc->wState & CBF_EDIT )
1349 EnableWindow32( lphc->hWndEdit, (BOOL32)wParam );
1350 EnableWindow32( lphc->hWndLBox, (BOOL32)wParam );
1351 return TRUE;
1353 case WM_SETREDRAW:
1354 if( wParam )
1355 lphc->wState &= ~CBF_NOREDRAW;
1356 else
1357 lphc->wState |= CBF_NOREDRAW;
1359 if( lphc->wState & CBF_EDIT )
1360 SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1361 SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1362 return 0;
1364 case WM_SYSKEYDOWN:
1365 if( KEYDATA_ALT & HIWORD(lParam) )
1366 if( wParam == VK_UP || wParam == VK_DOWN )
1367 COMBO_FlipListbox( lphc, TRUE );
1368 break;
1370 case WM_CHAR:
1371 case WM_KEYDOWN:
1372 if( lphc->wState & CBF_EDIT )
1373 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1374 else
1375 return SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1377 case WM_LBUTTONDOWN:
1378 if( !(lphc->wState & CBF_FOCUSED) ) SetFocus32( lphc->self->hwndSelf );
1379 if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
1380 return TRUE;
1382 case WM_LBUTTONUP:
1383 COMBO_LButtonUp( lphc, lParam );
1384 return TRUE;
1386 case WM_MOUSEMOVE:
1387 if( lphc->wState & CBF_CAPTURE )
1388 COMBO_MouseMove( lphc, wParam, lParam );
1389 return TRUE;
1391 /* Combo messages */
1393 case CB_ADDSTRING16:
1394 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1395 case CB_ADDSTRING32:
1396 return SendMessage32A( lphc->hWndLBox, LB_ADDSTRING32, 0, lParam);
1398 case CB_INSERTSTRING16:
1399 wParam = (INT32)(INT16)wParam;
1400 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1401 case CB_INSERTSTRING32:
1402 return SendMessage32A( lphc->hWndLBox, LB_INSERTSTRING32, wParam, lParam);
1404 case CB_DELETESTRING16:
1405 case CB_DELETESTRING32:
1406 return SendMessage32A( lphc->hWndLBox, LB_DELETESTRING32, wParam, 0);
1408 case CB_SELECTSTRING16:
1409 wParam = (INT32)(INT16)wParam;
1410 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1411 case CB_SELECTSTRING32:
1412 return COMBO_SelectString( lphc, (INT32)wParam, (LPSTR)lParam );
1414 case CB_FINDSTRING16:
1415 wParam = (INT32)(INT16)wParam;
1416 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1417 case CB_FINDSTRING32:
1418 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, wParam, lParam);
1420 case CB_FINDSTRINGEXACT16:
1421 wParam = (INT32)(INT16)wParam;
1422 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1423 case CB_FINDSTRINGEXACT32:
1424 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRINGEXACT32,
1425 wParam, lParam );
1426 case CB_SETITEMHEIGHT16:
1427 wParam = (INT32)(INT16)wParam; /* signed integer */
1428 case CB_SETITEMHEIGHT32:
1429 return COMBO_SetItemHeight( lphc, (INT32)wParam, (INT32)lParam);
1431 case CB_GETITEMHEIGHT16:
1432 wParam = (INT32)(INT16)wParam;
1433 case CB_GETITEMHEIGHT32:
1434 if( (INT32)wParam >= 0 )
1435 return SendMessage32A( lphc->hWndLBox, LB_GETITEMHEIGHT32, wParam, 0);
1436 return (lphc->RectEdit.bottom - lphc->RectEdit.top);
1438 case CB_RESETCONTENT16:
1439 case CB_RESETCONTENT32:
1440 SendMessage32A( lphc->hWndLBox, LB_RESETCONTENT32, 0, 0 );
1441 CBPaintText( lphc, 0 );
1442 return TRUE;
1444 case CB_INITSTORAGE32:
1445 return SendMessage32A( lphc->hWndLBox, LB_INITSTORAGE32, wParam, lParam);
1447 case CB_GETHORIZONTALEXTENT32:
1448 return SendMessage32A( lphc->hWndLBox, LB_GETHORIZONTALEXTENT32, 0, 0);
1450 case CB_SETHORIZONTALEXTENT32:
1451 return SendMessage32A( lphc->hWndLBox, LB_SETHORIZONTALEXTENT32, wParam, 0);
1453 case CB_GETTOPINDEX32:
1454 return SendMessage32A( lphc->hWndLBox, LB_GETTOPINDEX32, 0, 0);
1456 case CB_GETLOCALE32:
1457 return SendMessage32A( lphc->hWndLBox, LB_GETLOCALE32, 0, 0);
1459 case CB_SETLOCALE32:
1460 return SendMessage32A( lphc->hWndLBox, LB_SETLOCALE32, wParam, 0);
1462 case CB_GETDROPPEDWIDTH32:
1463 if( lphc->droppedWidth )
1464 return lphc->droppedWidth;
1465 return lphc->RectCombo.right - lphc->RectCombo.left -
1466 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
1468 case CB_SETDROPPEDWIDTH32:
1469 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
1470 (INT32)wParam < 32768 ) lphc->droppedWidth = (INT32)wParam;
1471 return CB_ERR;
1473 case CB_GETDROPPEDCONTROLRECT16:
1474 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1475 if( lParam )
1477 RECT32 r;
1478 CBGetDroppedControlRect32( lphc, &r );
1479 CONV_RECT32TO16( &r, (LPRECT16)lParam );
1481 return CB_OKAY;
1483 case CB_GETDROPPEDCONTROLRECT32:
1484 if( lParam ) CBGetDroppedControlRect32(lphc, (LPRECT32)lParam );
1485 return CB_OKAY;
1487 case CB_GETDROPPEDSTATE16:
1488 case CB_GETDROPPEDSTATE32:
1489 return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
1491 case CB_DIR16:
1492 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1493 /* fall through */
1494 case CB_DIR32:
1495 return COMBO_Directory( lphc, (UINT32)wParam,
1496 (LPSTR)lParam, (message == CB_DIR32));
1497 case CB_SHOWDROPDOWN16:
1498 case CB_SHOWDROPDOWN32:
1499 if( CB_GETTYPE(lphc) != CBS_SIMPLE ) {
1500 if( wParam ) {
1501 if( !(lphc->wState & CBF_DROPPED) )
1502 CBDropDown( lphc );
1503 } else {
1504 if( lphc->wState & CBF_DROPPED )
1505 CBRollUp( lphc, FALSE, TRUE );
1508 return TRUE;
1510 case CB_GETCOUNT16:
1511 case CB_GETCOUNT32:
1512 return SendMessage32A( lphc->hWndLBox, LB_GETCOUNT32, 0, 0);
1514 case CB_GETCURSEL16:
1515 case CB_GETCURSEL32:
1516 return SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0);
1518 case CB_SETCURSEL16:
1519 wParam = (INT32)(INT16)wParam;
1520 case CB_SETCURSEL32:
1521 return SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, wParam, 0);
1523 case CB_GETLBTEXT16:
1524 wParam = (INT32)(INT16)wParam;
1525 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1526 case CB_GETLBTEXT32:
1527 return SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, wParam, lParam);
1529 case CB_GETLBTEXTLEN16:
1530 wParam = (INT32)(INT16)wParam;
1531 case CB_GETLBTEXTLEN32:
1532 return SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, wParam, 0);
1534 case CB_GETITEMDATA16:
1535 wParam = (INT32)(INT16)wParam;
1536 case CB_GETITEMDATA32:
1537 return SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32, wParam, 0);
1539 case CB_SETITEMDATA16:
1540 wParam = (INT32)(INT16)wParam;
1541 case CB_SETITEMDATA32:
1542 return SendMessage32A( lphc->hWndLBox, LB_SETITEMDATA32, wParam, lParam);
1544 case CB_GETEDITSEL16:
1545 wParam = lParam = 0; /* just in case */
1546 case CB_GETEDITSEL32:
1547 if( lphc->wState & CBF_EDIT )
1549 INT32 a, b;
1551 return SendMessage32A( lphc->hWndEdit, EM_GETSEL32,
1552 (wParam) ? wParam : (WPARAM32)&a,
1553 (lParam) ? lParam : (LPARAM)&b );
1555 return CB_ERR;
1557 case CB_SETEDITSEL16:
1558 case CB_SETEDITSEL32:
1559 if( lphc->wState & CBF_EDIT )
1560 return SendMessage32A( lphc->hWndEdit, EM_SETSEL32,
1561 (INT32)(INT16)LOWORD(lParam), (INT32)(INT16)HIWORD(lParam) );
1562 return CB_ERR;
1564 case CB_SETEXTENDEDUI16:
1565 case CB_SETEXTENDEDUI32:
1566 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR;
1568 if( wParam )
1569 lphc->wState |= CBF_EUI;
1570 else lphc->wState &= ~CBF_EUI;
1571 return CB_OKAY;
1573 case CB_GETEXTENDEDUI16:
1574 case CB_GETEXTENDEDUI32:
1575 return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
1577 case (WM_USER + 0x1B):
1578 WARN(combo, "[%04x]: undocumented msg!\n", hwnd );
1580 return DefWindowProc32A(hwnd, message, wParam, lParam);
1582 return CB_ERR;